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.Configuration; 31 import android.content.res.Resources; 32 import android.os.Bundle; 33 import android.os.UserManager; 34 import android.os.Vibrator; 35 import android.telephony.SubscriptionManager; 36 import android.util.Log; 37 import android.view.LayoutInflater; 38 import android.view.MenuItem; 39 import android.view.View; 40 import android.view.ViewGroup; 41 import android.widget.CompoundButton; 42 import android.widget.CompoundButton.OnCheckedChangeListener; 43 44 import androidx.localbroadcastmanager.content.LocalBroadcastManager; 45 import androidx.preference.ListPreference; 46 import androidx.preference.Preference; 47 import androidx.preference.PreferenceCategory; 48 import androidx.preference.PreferenceFragment; 49 import androidx.preference.PreferenceManager; 50 import androidx.preference.PreferenceScreen; 51 import androidx.preference.TwoStatePreference; 52 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.modules.utils.build.SdkLevel; 55 import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; 56 import com.android.settingslib.widget.MainSwitchPreference; 57 58 import java.util.HashMap; 59 import java.util.Map; 60 61 /** 62 * Settings activity for the cell broadcast receiver. 63 */ 64 public class CellBroadcastSettings extends CollapsingToolbarBaseActivity { 65 66 private static final String TAG = "CellBroadcastSettings"; 67 68 private static final boolean DBG = false; 69 70 @VisibleForTesting 71 public CellBroadcastSettings.CellBroadcastSettingsFragment mCellBroadcastSettingsFragment; 72 73 /** 74 * Keys for user preferences. 75 * When adding a new preference, make sure to clear its value in resetAllPreferences. 76 */ 77 // Preference key for alert header (A text view, not clickable). 78 public static final String KEY_ALERTS_HEADER = "alerts_header"; 79 80 // Preference key for a main toggle to enable/disable all alerts message (default enabled). 81 public static final String KEY_ENABLE_ALERTS_MASTER_TOGGLE = "enable_alerts_master_toggle"; 82 83 // Preference key for whether to enable public safety messages (default enabled). 84 public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES = "enable_public_safety_messages"; 85 86 // Preference key for whether to show full-screen public safety message (pop-up dialog), If set 87 // to false, only display from message history and sms inbox if enabled. A foreground 88 // notification might also be shown if enabled. 89 public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN = 90 "enable_public_safety_messages_full_screen"; 91 92 // Preference key for whether to enable emergency alerts (default enabled). 93 public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts"; 94 95 // Enable vibration on alert (unless main volume is silent). 96 public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate"; 97 98 // Speak contents of alert after playing the alert sound. 99 public static final String KEY_ENABLE_ALERT_SPEECH = "enable_alert_speech"; 100 101 // Play alert sound in full volume regardless Do Not Disturb is on. 102 public static final String KEY_OVERRIDE_DND = "override_dnd"; 103 104 public static final String KEY_OVERRIDE_DND_SETTINGS_CHANGED = 105 "override_dnd_settings_changed"; 106 107 // Preference category for emergency alert and CMAS settings. 108 public static final String KEY_CATEGORY_EMERGENCY_ALERTS = "category_emergency_alerts"; 109 110 // Preference category for alert preferences. 111 public static final String KEY_CATEGORY_ALERT_PREFERENCES = "category_alert_preferences"; 112 113 // Show checkbox for Presidential alerts in settings 114 // Whether to display CMAS presidential alert notifications (always enabled). 115 public static final String KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS = 116 "enable_cmas_presidential_alerts"; 117 118 // Whether to display CMAS extreme threat notifications (default is enabled). 119 public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS = 120 "enable_cmas_extreme_threat_alerts"; 121 122 // Whether to display CMAS severe threat notifications (default is enabled). 123 public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS = 124 "enable_cmas_severe_threat_alerts"; 125 126 // Whether to display CMAS amber alert messages (default is enabled). 127 public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts"; 128 129 // Whether to display monthly test messages (default is disabled). 130 public static final String KEY_ENABLE_TEST_ALERTS = "enable_test_alerts"; 131 132 // Whether to display exercise test alerts. 133 public static final String KEY_ENABLE_EXERCISE_ALERTS = "enable_exercise_alerts"; 134 135 // Whether to display operator defined test alerts 136 public static final String KEY_OPERATOR_DEFINED_ALERTS = "enable_operator_defined_alerts"; 137 138 // Whether to display state/local test messages (default disabled). 139 public static final String KEY_ENABLE_STATE_LOCAL_TEST_ALERTS = 140 "enable_state_local_test_alerts"; 141 142 // Preference key for whether to enable area update information notifications 143 // Enabled by default for phones sold in Brazil and India, otherwise this setting may be hidden. 144 public static final String KEY_ENABLE_AREA_UPDATE_INFO_ALERTS = 145 "enable_area_update_info_alerts"; 146 147 // Preference key for initial opt-in/opt-out dialog. 148 public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog"; 149 150 // Alert reminder interval ("once" = single 2 minute reminder). 151 public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval"; 152 153 // Preference key for emergency alerts history 154 public static final String KEY_EMERGENCY_ALERT_HISTORY = "emergency_alert_history"; 155 156 // For top introduction info 157 @VisibleForTesting 158 public static final String KEY_PREFS_TOP_INTRO = "alert_prefs_top_intro"; 159 160 // Whether to receive alert in second language code 161 public static final String KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE = 162 "receive_cmas_in_second_language"; 163 164 /* End of user preferences keys section. */ 165 166 // Key for shared preference which represents whether user has changed any preference 167 @VisibleForTesting 168 public static final String ANY_PREFERENCE_CHANGED_BY_USER = "any_preference_changed_by_user"; 169 170 // Resource cache per operator 171 @VisibleForTesting 172 public static final Map<String, Resources> sResourcesCacheByOperator = new HashMap<>(); 173 private static final Object sCacheLock = new Object(); 174 175 // Intent sent from cellbroadcastreceiver to notify cellbroadcastservice that area info update 176 // is disabled/enabled. 177 private static final String AREA_INFO_UPDATE_ACTION = 178 "com.android.cellbroadcastreceiver.action.AREA_UPDATE_INFO_ENABLED"; 179 private static final String AREA_INFO_UPDATE_ENABLED_EXTRA = "enable"; 180 181 /** 182 * This permission is only granted to the cellbroadcast mainline module and thus can be 183 * used for permission check within CBR and CBS. 184 */ 185 private static final String CBR_MODULE_PERMISSION = 186 "com.android.cellbroadcastservice.FULL_ACCESS_CELL_BROADCAST_HISTORY"; 187 188 @Override onCreate(Bundle savedInstanceState)189 public void onCreate(Bundle savedInstanceState) { 190 boolean isWatch = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); 191 // for backward compatibility on R devices or wearable devices due to small screen device. 192 boolean hideToolbar = !SdkLevel.isAtLeastS() || isWatch; 193 if (hideToolbar) { 194 setCustomizeContentView(R.layout.cell_broadcast_list_collapsing_no_toobar); 195 } 196 197 super.onCreate(savedInstanceState); 198 199 if (hideToolbar) { 200 ActionBar actionBar = getActionBar(); 201 if (actionBar != null) { 202 // android.R.id.home will be triggered in onOptionsItemSelected() 203 actionBar.setDisplayHomeAsUpEnabled(true); 204 } 205 } 206 207 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); 208 if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) { 209 setContentView(R.layout.cell_broadcast_disallowed_preference_screen); 210 return; 211 } 212 213 // We only add new CellBroadcastSettingsFragment if no fragment is restored. 214 Fragment fragment = getFragmentManager().findFragmentById( 215 com.android.settingslib.collapsingtoolbar.R.id.content_frame); 216 if (fragment == null) { 217 mCellBroadcastSettingsFragment = new CellBroadcastSettingsFragment(); 218 getFragmentManager() 219 .beginTransaction() 220 .add(com.android.settingslib.collapsingtoolbar.R.id.content_frame, 221 mCellBroadcastSettingsFragment) 222 .commit(); 223 } 224 } 225 226 @Override onStart()227 public void onStart() { 228 super.onStart(); 229 getWindow().addSystemFlags( 230 android.view.WindowManager.LayoutParams 231 .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 232 } 233 234 @Override onOptionsItemSelected(MenuItem item)235 public boolean onOptionsItemSelected(MenuItem item) { 236 switch (item.getItemId()) { 237 // Respond to the action bar's Up/Home button 238 case android.R.id.home: 239 finish(); 240 return true; 241 } 242 return super.onOptionsItemSelected(item); 243 } 244 245 /** 246 * Reset all user values for preferences (stored in shared preferences). 247 * 248 * @param c the application context 249 */ resetAllPreferences(Context c)250 public static void resetAllPreferences(Context c) { 251 SharedPreferences.Editor e = PreferenceManager.getDefaultSharedPreferences(c).edit(); 252 e.remove(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS) 253 .remove(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS) 254 .remove(KEY_ENABLE_CMAS_AMBER_ALERTS) 255 .remove(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES) 256 .remove(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN) 257 .remove(KEY_ENABLE_EMERGENCY_ALERTS) 258 .remove(KEY_ALERT_REMINDER_INTERVAL) 259 .remove(KEY_ENABLE_ALERT_SPEECH) 260 .remove(KEY_OVERRIDE_DND) 261 .remove(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS) 262 .remove(KEY_ENABLE_TEST_ALERTS) 263 .remove(KEY_ENABLE_STATE_LOCAL_TEST_ALERTS) 264 .remove(KEY_ENABLE_ALERT_VIBRATE) 265 .remove(KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS) 266 .remove(KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE) 267 .remove(KEY_ENABLE_EXERCISE_ALERTS) 268 .remove(KEY_OPERATOR_DEFINED_ALERTS); 269 // If the device is in test harness mode, reset main toggle should only happen on the 270 // first boot. 271 if (!ActivityManager.isRunningInUserTestHarness()) { 272 Log.d(TAG, "In not test harness mode. reset main toggle."); 273 e.remove(KEY_ENABLE_ALERTS_MASTER_TOGGLE); 274 } 275 e.commit(); 276 277 PackageManager pm = c.getPackageManager(); 278 if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 279 PreferenceManager.setDefaultValues(c, R.xml.watch_preferences, true); 280 } else { 281 PreferenceManager.setDefaultValues(c, R.xml.preferences, true); 282 } 283 setPreferenceChanged(c, false); 284 } 285 286 /** 287 * Return true if user has modified any preference manually. 288 * @param c the application context 289 * @return 290 */ hasAnyPreferenceChanged(Context c)291 public static boolean hasAnyPreferenceChanged(Context c) { 292 return PreferenceManager.getDefaultSharedPreferences(c) 293 .getBoolean(ANY_PREFERENCE_CHANGED_BY_USER, false); 294 } 295 setPreferenceChanged(Context c, boolean changed)296 private static void setPreferenceChanged(Context c, boolean changed) { 297 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(c); 298 sp.edit().putBoolean(ANY_PREFERENCE_CHANGED_BY_USER, changed).apply(); 299 } 300 301 /** 302 * New fragment-style implementation of preferences. 303 */ 304 public static class CellBroadcastSettingsFragment extends PreferenceFragment { 305 306 private TwoStatePreference mExtremeCheckBox; 307 private TwoStatePreference mSevereCheckBox; 308 private TwoStatePreference mAmberCheckBox; 309 private TwoStatePreference mMasterToggle; 310 private TwoStatePreference mPublicSafetyMessagesChannelCheckBox; 311 private TwoStatePreference mPublicSafetyMessagesChannelFullScreenCheckBox; 312 private TwoStatePreference mEmergencyAlertsCheckBox; 313 private ListPreference mReminderInterval; 314 private TwoStatePreference mSpeechCheckBox; 315 private TwoStatePreference mOverrideDndCheckBox; 316 private TwoStatePreference mAreaUpdateInfoCheckBox; 317 private TwoStatePreference mTestCheckBox; 318 private TwoStatePreference mExerciseTestCheckBox; 319 private TwoStatePreference mOperatorDefinedCheckBox; 320 private TwoStatePreference mStateLocalTestCheckBox; 321 private TwoStatePreference mEnableVibrateCheckBox; 322 private Preference mAlertHistory; 323 private Preference mAlertsHeader; 324 private PreferenceCategory mAlertCategory; 325 private PreferenceCategory mAlertPreferencesCategory; 326 private boolean mDisableSevereWhenExtremeDisabled = true; 327 328 // Show checkbox for Presidential alerts in settings 329 private TwoStatePreference mPresidentialCheckBox; 330 331 // on/off switch in settings for receiving alert in second language code 332 private TwoStatePreference mReceiveCmasInSecondLanguageCheckBox; 333 334 // Show the top introduction 335 private Preference mTopIntroPreference; 336 337 private final BroadcastReceiver mTestingModeChangedReceiver = new BroadcastReceiver() { 338 @Override 339 public void onReceive(Context context, Intent intent) { 340 switch (intent.getAction()) { 341 case CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED: 342 updatePreferenceVisibility(); 343 break; 344 } 345 } 346 }; 347 initPreferences()348 private void initPreferences() { 349 mExtremeCheckBox = (TwoStatePreference) 350 findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS); 351 mSevereCheckBox = (TwoStatePreference) 352 findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS); 353 mAmberCheckBox = (TwoStatePreference) 354 findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS); 355 mMasterToggle = (TwoStatePreference) 356 findPreference(KEY_ENABLE_ALERTS_MASTER_TOGGLE); 357 mPublicSafetyMessagesChannelCheckBox = (TwoStatePreference) 358 findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES); 359 mPublicSafetyMessagesChannelFullScreenCheckBox = (TwoStatePreference) 360 findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN); 361 mEmergencyAlertsCheckBox = (TwoStatePreference) 362 findPreference(KEY_ENABLE_EMERGENCY_ALERTS); 363 mReminderInterval = (ListPreference) 364 findPreference(KEY_ALERT_REMINDER_INTERVAL); 365 mSpeechCheckBox = (TwoStatePreference) 366 findPreference(KEY_ENABLE_ALERT_SPEECH); 367 mOverrideDndCheckBox = (TwoStatePreference) 368 findPreference(KEY_OVERRIDE_DND); 369 mAreaUpdateInfoCheckBox = (TwoStatePreference) 370 findPreference(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS); 371 mTestCheckBox = (TwoStatePreference) 372 findPreference(KEY_ENABLE_TEST_ALERTS); 373 mExerciseTestCheckBox = (TwoStatePreference) findPreference(KEY_ENABLE_EXERCISE_ALERTS); 374 mOperatorDefinedCheckBox = (TwoStatePreference) 375 findPreference(KEY_OPERATOR_DEFINED_ALERTS); 376 mStateLocalTestCheckBox = (TwoStatePreference) 377 findPreference(KEY_ENABLE_STATE_LOCAL_TEST_ALERTS); 378 mAlertHistory = findPreference(KEY_EMERGENCY_ALERT_HISTORY); 379 mAlertsHeader = findPreference(KEY_ALERTS_HEADER); 380 mReceiveCmasInSecondLanguageCheckBox = (TwoStatePreference) findPreference 381 (KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE); 382 mEnableVibrateCheckBox = findPreference(KEY_ENABLE_ALERT_VIBRATE); 383 384 // Show checkbox for Presidential alerts in settings 385 mPresidentialCheckBox = (TwoStatePreference) 386 findPreference(KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS); 387 388 PackageManager pm = getActivity().getPackageManager(); 389 if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 390 mAlertPreferencesCategory = (PreferenceCategory) 391 findPreference(KEY_CATEGORY_ALERT_PREFERENCES); 392 mAlertCategory = (PreferenceCategory) 393 findPreference(KEY_CATEGORY_EMERGENCY_ALERTS); 394 } 395 mTopIntroPreference = findPreference(KEY_PREFS_TOP_INTRO); 396 } 397 398 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)399 public View onCreateView(LayoutInflater inflater, ViewGroup container, 400 Bundle savedInstanceState) { 401 View root = super.onCreateView(inflater, container, savedInstanceState); 402 PackageManager pm = getActivity().getPackageManager(); 403 if (pm != null 404 && pm.hasSystemFeature( 405 PackageManager.FEATURE_WATCH)) { 406 ViewGroup.LayoutParams layoutParams = getListView().getLayoutParams(); 407 if (layoutParams instanceof ViewGroup.MarginLayoutParams) { 408 int watchMarginInPixel = (int) getResources().getDimension( 409 R.dimen.pref_top_margin); 410 ((ViewGroup.MarginLayoutParams) layoutParams).topMargin = watchMarginInPixel; 411 ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = watchMarginInPixel; 412 getListView().setLayoutParams(layoutParams); 413 } 414 } 415 return root; 416 } 417 418 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)419 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 420 421 LocalBroadcastManager.getInstance(getContext()) 422 .registerReceiver(mTestingModeChangedReceiver, new IntentFilter( 423 CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED)); 424 425 // Load the preferences from an XML resource 426 PackageManager pm = getActivity().getPackageManager(); 427 if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) { 428 addPreferencesFromResource(R.xml.watch_preferences); 429 } else { 430 addPreferencesFromResource(R.xml.preferences); 431 } 432 433 initPreferences(); 434 435 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 436 437 mDisableSevereWhenExtremeDisabled = res.getBoolean( 438 R.bool.disable_severe_when_extreme_disabled); 439 440 // Handler for settings that require us to reconfigure enabled channels in radio 441 Preference.OnPreferenceChangeListener startConfigServiceListener = 442 new Preference.OnPreferenceChangeListener() { 443 @Override 444 public boolean onPreferenceChange(Preference pref, Object newValue) { 445 if (mDisableSevereWhenExtremeDisabled) { 446 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) { 447 boolean isExtremeAlertChecked = (Boolean) newValue; 448 if (mSevereCheckBox != null) { 449 mSevereCheckBox.setEnabled(isExtremeAlertChecked); 450 mSevereCheckBox.setChecked(false); 451 } 452 } 453 } 454 455 // check if area update was disabled 456 if (pref.getKey().equals(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS)) { 457 boolean isEnabledAlert = (Boolean) newValue; 458 notifyAreaInfoUpdate(isEnabledAlert); 459 } 460 461 onPreferenceChangedByUser(getContext(), true); 462 return true; 463 } 464 }; 465 466 Preference.OnPreferenceChangeListener alertPreferenceToggleListener = 467 new Preference.OnPreferenceChangeListener() { 468 @Override 469 public boolean onPreferenceChange(Preference pref, Object newValue) { 470 onPreferenceChangedByUser(getContext(), false); 471 return true; 472 } 473 }; 474 475 initReminderIntervalList(); 476 477 if (mMasterToggle != null) { 478 479 initAlertsToggleDisabledAsNeeded(); 480 481 if (mMasterToggle instanceof MainSwitchPreference) { 482 MainSwitchPreference mainSwitchPreference = 483 (MainSwitchPreference) mMasterToggle; 484 final OnCheckedChangeListener mainSwitchListener = 485 new OnCheckedChangeListener() { 486 @Override 487 public void onCheckedChanged(CompoundButton buttonView, 488 boolean isChecked) { 489 setAlertsEnabled(isChecked); 490 onPreferenceChangedByUser(getContext(), true); 491 } 492 }; 493 mainSwitchPreference.addOnSwitchChangeListener(mainSwitchListener); 494 } else { 495 Preference.OnPreferenceChangeListener mainSwitchListener = 496 new Preference.OnPreferenceChangeListener() { 497 @Override 498 public boolean onPreferenceChange( 499 Preference pref, Object newValue) { 500 setAlertsEnabled((Boolean) newValue); 501 onPreferenceChangedByUser(getContext(), true); 502 return true; 503 } 504 }; 505 mMasterToggle.setOnPreferenceChangeListener(mainSwitchListener); 506 } 507 // If allow alerts are disabled, we turn all sub-alerts off. If it's enabled, we 508 // leave them as they are. 509 if (!mMasterToggle.isChecked()) { 510 setAlertsEnabled(false); 511 } 512 } 513 // note that mPresidentialCheckBox does not use the startConfigServiceListener because 514 // the user is never allowed to change the preference 515 if (mAreaUpdateInfoCheckBox != null) { 516 mAreaUpdateInfoCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 517 } 518 if (mExtremeCheckBox != null) { 519 mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 520 } 521 if (mPublicSafetyMessagesChannelCheckBox != null) { 522 mPublicSafetyMessagesChannelCheckBox.setOnPreferenceChangeListener( 523 startConfigServiceListener); 524 } 525 if (mPublicSafetyMessagesChannelFullScreenCheckBox != null) { 526 mPublicSafetyMessagesChannelFullScreenCheckBox.setOnPreferenceChangeListener( 527 startConfigServiceListener); 528 } 529 if (mEmergencyAlertsCheckBox != null) { 530 mEmergencyAlertsCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 531 } 532 if (mSevereCheckBox != null) { 533 mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 534 if (mDisableSevereWhenExtremeDisabled) { 535 if (mExtremeCheckBox != null) { 536 mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked()); 537 } 538 } 539 } 540 if (mAmberCheckBox != null) { 541 mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 542 } 543 if (mTestCheckBox != null) { 544 mTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 545 } 546 if (mExerciseTestCheckBox != null) { 547 mExerciseTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 548 } 549 if (mOperatorDefinedCheckBox != null) { 550 mOperatorDefinedCheckBox.setOnPreferenceChangeListener(startConfigServiceListener); 551 } 552 if (mStateLocalTestCheckBox != null) { 553 mStateLocalTestCheckBox.setOnPreferenceChangeListener( 554 startConfigServiceListener); 555 } 556 557 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); 558 559 if (mOverrideDndCheckBox != null) { 560 if (!sp.getBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED, false)) { 561 // If the user hasn't changed this settings yet, use the default settings 562 // from resource overlay. 563 mOverrideDndCheckBox.setChecked(res.getBoolean(R.bool.override_dnd_default)); 564 } 565 mOverrideDndCheckBox.setOnPreferenceChangeListener( 566 (pref, newValue) -> { 567 sp.edit().putBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED, 568 true).apply(); 569 updateVibrationPreference((boolean) newValue); 570 return true; 571 }); 572 } 573 574 if (mAlertHistory != null) { 575 mAlertHistory.setOnPreferenceClickListener( 576 preference -> { 577 final Intent intent = new Intent(getContext(), 578 CellBroadcastListActivity.class); 579 startActivity(intent); 580 return true; 581 }); 582 } 583 584 if (mSpeechCheckBox != null) { 585 mSpeechCheckBox.setOnPreferenceChangeListener(alertPreferenceToggleListener); 586 } 587 588 updateVibrationPreference(sp.getBoolean(CellBroadcastSettings.KEY_OVERRIDE_DND, 589 false)); 590 updatePreferenceVisibility(); 591 } 592 593 /** 594 * Update the vibration preference based on override DND. If DND is overridden, then do 595 * not allow users to turn off vibration. 596 * 597 * @param overrideDnd {@code true} if the alert will be played at full volume, regardless 598 * DND settings. 599 */ updateVibrationPreference(boolean overrideDnd)600 private void updateVibrationPreference(boolean overrideDnd) { 601 if (mEnableVibrateCheckBox != null) { 602 if (overrideDnd) { 603 // If DND is enabled, always enable vibration. 604 mEnableVibrateCheckBox.setChecked(true); 605 } 606 // Grey out the preference if DND is overridden. 607 mEnableVibrateCheckBox.setEnabled(!overrideDnd); 608 } 609 } 610 611 /** 612 * Dynamically update each preference's visibility based on configuration. 613 */ updatePreferenceVisibility()614 private void updatePreferenceVisibility() { 615 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 616 617 // The settings should be based on the config by the subscription 618 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( 619 getContext(), SubscriptionManager.getDefaultSubscriptionId(), null); 620 621 PreferenceScreen preferenceScreen = getPreferenceScreen(); 622 boolean isWatch = getActivity().getPackageManager().hasSystemFeature( 623 PackageManager.FEATURE_WATCH); 624 625 if (mMasterToggle != null) { 626 mMasterToggle.setVisible(res.getBoolean(R.bool.show_main_switch_settings)); 627 } 628 629 if (mPresidentialCheckBox != null) { 630 mPresidentialCheckBox.setVisible( 631 res.getBoolean(R.bool.show_presidential_alerts_settings)); 632 if (isWatch && !mPresidentialCheckBox.isVisible()) { 633 preferenceScreen.removePreference(mPresidentialCheckBox); 634 } 635 } 636 637 if (mExtremeCheckBox != null) { 638 mExtremeCheckBox.setVisible(res.getBoolean(R.bool.show_extreme_alert_settings) 639 && !channelManager.getCellBroadcastChannelRanges( 640 R.array.cmas_alert_extreme_channels_range_strings).isEmpty()); 641 if (isWatch && !mExtremeCheckBox.isVisible()) { 642 preferenceScreen.removePreference(mExtremeCheckBox); 643 } 644 } 645 646 if (mSevereCheckBox != null) { 647 mSevereCheckBox.setVisible(res.getBoolean(R.bool.show_severe_alert_settings) 648 && !channelManager.getCellBroadcastChannelRanges( 649 R.array.cmas_alerts_severe_range_strings).isEmpty()); 650 if (isWatch && !mSevereCheckBox.isVisible()) { 651 preferenceScreen.removePreference(mSevereCheckBox); 652 } 653 } 654 655 if (mAmberCheckBox != null) { 656 mAmberCheckBox.setVisible(res.getBoolean(R.bool.show_amber_alert_settings) 657 && !channelManager.getCellBroadcastChannelRanges( 658 R.array.cmas_amber_alerts_channels_range_strings).isEmpty()); 659 if (isWatch && !mAmberCheckBox.isVisible()) { 660 preferenceScreen.removePreference(mAmberCheckBox); 661 } 662 } 663 664 if (mPublicSafetyMessagesChannelCheckBox != null) { 665 mPublicSafetyMessagesChannelCheckBox.setVisible( 666 res.getBoolean(R.bool.show_public_safety_settings) 667 && !channelManager.getCellBroadcastChannelRanges( 668 R.array.public_safety_messages_channels_range_strings) 669 .isEmpty()); 670 if (isWatch && !mPublicSafetyMessagesChannelCheckBox.isVisible()) { 671 preferenceScreen.removePreference(mPublicSafetyMessagesChannelCheckBox); 672 } 673 } 674 // this is the matching full screen settings for public safety toggle. shown only if 675 // public safety toggle is displayed. 676 if (mPublicSafetyMessagesChannelFullScreenCheckBox != null) { 677 mPublicSafetyMessagesChannelFullScreenCheckBox.setVisible( 678 isShowFullScreenMessageVisible(getContext(), res)); 679 } 680 681 if (mTestCheckBox != null) { 682 mTestCheckBox.setVisible(isTestAlertsToggleVisible(getContext())); 683 } 684 685 if (mExerciseTestCheckBox != null) { 686 mExerciseTestCheckBox.setVisible( 687 isExerciseTestAlertsToggleVisible(res, getContext(), channelManager)); 688 } 689 690 if (mOperatorDefinedCheckBox != null) { 691 mOperatorDefinedCheckBox.setVisible( 692 isOperatorTestAlertsToggleVisible(res, getContext(), channelManager)); 693 } 694 695 if (mEmergencyAlertsCheckBox != null) { 696 mEmergencyAlertsCheckBox.setVisible(!channelManager.getCellBroadcastChannelRanges( 697 R.array.emergency_alerts_channels_range_strings).isEmpty()); 698 if (isWatch && !mEmergencyAlertsCheckBox.isVisible()) { 699 preferenceScreen.removePreference(mEmergencyAlertsCheckBox); 700 } 701 } 702 703 if (mStateLocalTestCheckBox != null) { 704 mStateLocalTestCheckBox.setVisible( 705 res.getBoolean(R.bool.show_state_local_test_settings) 706 && !channelManager.getCellBroadcastChannelRanges( 707 R.array.state_local_test_alert_range_strings).isEmpty()); 708 if (isWatch && !mStateLocalTestCheckBox.isVisible()) { 709 preferenceScreen.removePreference(mStateLocalTestCheckBox); 710 } 711 } 712 713 if (mReceiveCmasInSecondLanguageCheckBox != null) { 714 mReceiveCmasInSecondLanguageCheckBox.setVisible(!res.getString( 715 R.string.emergency_alert_second_language_code).isEmpty()); 716 if (isWatch && !mReceiveCmasInSecondLanguageCheckBox.isVisible()) { 717 preferenceScreen.removePreference(mReceiveCmasInSecondLanguageCheckBox); 718 } 719 } 720 721 if (mAreaUpdateInfoCheckBox != null) { 722 mAreaUpdateInfoCheckBox.setVisible( 723 res.getBoolean(R.bool.config_showAreaUpdateInfoSettings)); 724 if (isWatch && !mAreaUpdateInfoCheckBox.isVisible()) { 725 preferenceScreen.removePreference(mAreaUpdateInfoCheckBox); 726 } 727 } 728 729 if (mOverrideDndCheckBox != null) { 730 mOverrideDndCheckBox.setVisible(res.getBoolean(R.bool.show_override_dnd_settings)); 731 if (isWatch && !mOverrideDndCheckBox.isVisible()) { 732 preferenceScreen.removePreference(mOverrideDndCheckBox); 733 } 734 } 735 736 if (mEnableVibrateCheckBox != null) { 737 // Only show vibrate toggle when override DND toggle is available to users, or when 738 // override DND default is turned off. 739 // In some countries, override DND is always on, which means vibration is always on. 740 // In that case, no need to show vibration toggle for users. 741 mEnableVibrateCheckBox.setVisible(isVibrationToggleVisible(getContext(), res)); 742 if (isWatch && !mEnableVibrateCheckBox.isVisible()) { 743 preferenceScreen.removePreference(mEnableVibrateCheckBox); 744 } 745 } 746 if (mAlertsHeader != null) { 747 mAlertsHeader.setVisible( 748 !getContext().getString(R.string.alerts_header_summary).isEmpty()); 749 if (isWatch && !mAlertsHeader.isVisible()) { 750 preferenceScreen.removePreference(mAlertsHeader); 751 } 752 } 753 754 if (mSpeechCheckBox != null) { 755 mSpeechCheckBox.setVisible(res.getBoolean(R.bool.show_alert_speech_setting) 756 || getActivity().getPackageManager() 757 .hasSystemFeature(PackageManager.FEATURE_WATCH)); 758 } 759 760 if (mTopIntroPreference != null) { 761 mTopIntroPreference.setTitle(getTopIntroduction()); 762 } 763 } 764 getTopIntroduction()765 private int getTopIntroduction() { 766 // Only set specific top introduction for roaming support now 767 if (!CellBroadcastReceiver.getRoamingOperatorSupported(getContext()).isEmpty()) { 768 return R.string.top_intro_roaming_text; 769 } 770 return R.string.top_intro_default_text; 771 } 772 initReminderIntervalList()773 private void initReminderIntervalList() { 774 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 775 776 String[] activeValues = 777 res.getStringArray(R.array.alert_reminder_interval_active_values); 778 String[] allEntries = res.getStringArray(R.array.alert_reminder_interval_entries); 779 String[] newEntries = new String[activeValues.length]; 780 781 // Only add active interval to the list 782 for (int i = 0; i < activeValues.length; i++) { 783 int index = mReminderInterval.findIndexOfValue(activeValues[i]); 784 if (index != -1) { 785 newEntries[i] = allEntries[index]; 786 if (DBG) Log.d(TAG, "Added " + allEntries[index]); 787 } else { 788 Log.e(TAG, "Can't find " + activeValues[i]); 789 } 790 } 791 792 mReminderInterval.setEntries(newEntries); 793 mReminderInterval.setEntryValues(activeValues); 794 mReminderInterval.setSummary(mReminderInterval.getEntry()); 795 mReminderInterval.setOnPreferenceChangeListener( 796 new Preference.OnPreferenceChangeListener() { 797 @Override 798 public boolean onPreferenceChange(Preference pref, Object newValue) { 799 final ListPreference listPref = (ListPreference) pref; 800 final int idx = listPref.findIndexOfValue((String) newValue); 801 listPref.setSummary(listPref.getEntries()[idx]); 802 return true; 803 } 804 }); 805 } 806 807 /** 808 * Set the extreme toggle disabled as needed. 809 */ 810 @VisibleForTesting initAlertsToggleDisabledAsNeeded()811 public void initAlertsToggleDisabledAsNeeded() { 812 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 813 if (res.getBoolean(R.bool.disable_extreme_alert_settings)) { 814 mExtremeCheckBox.setEnabled(false); 815 mExtremeCheckBox.setChecked( 816 res.getBoolean(R.bool.extreme_threat_alerts_enabled_default)); 817 } 818 } 819 820 /** 821 * Enable the toggles to set it on/off or carrier default. 822 */ 823 @VisibleForTesting setAlertsEnabled(boolean alertsEnabled)824 public void setAlertsEnabled(boolean alertsEnabled) { 825 Resources res = CellBroadcastSettings.getResourcesForDefaultSubId(getContext()); 826 827 boolean resetCarrierDefault = res.getBoolean( 828 R.bool.restore_sub_toggle_to_carrier_default); 829 830 if (mSevereCheckBox != null) { 831 mSevereCheckBox.setEnabled(alertsEnabled); 832 mSevereCheckBox.setChecked(resetCarrierDefault ? alertsEnabled && res.getBoolean( 833 R.bool.severe_threat_alerts_enabled_default) : alertsEnabled); 834 } 835 if (!res.getBoolean(R.bool.disable_extreme_alert_settings) 836 && mExtremeCheckBox != null) { 837 mExtremeCheckBox.setEnabled(alertsEnabled); 838 mExtremeCheckBox.setChecked(resetCarrierDefault ? alertsEnabled && res.getBoolean( 839 R.bool.extreme_threat_alerts_enabled_default) : alertsEnabled); 840 } 841 if (mAmberCheckBox != null) { 842 mAmberCheckBox.setEnabled(alertsEnabled); 843 mAmberCheckBox.setChecked(resetCarrierDefault ? alertsEnabled && res.getBoolean( 844 R.bool.amber_alerts_enabled_default) : alertsEnabled); 845 } 846 if (mAreaUpdateInfoCheckBox != null) { 847 mAreaUpdateInfoCheckBox.setEnabled(alertsEnabled); 848 mAreaUpdateInfoCheckBox.setChecked( 849 resetCarrierDefault ? alertsEnabled && res.getBoolean( 850 R.bool.area_update_info_alerts_enabled_default) : alertsEnabled); 851 notifyAreaInfoUpdate(resetCarrierDefault ? alertsEnabled && res.getBoolean( 852 R.bool.area_update_info_alerts_enabled_default) : alertsEnabled); 853 } 854 if (mEmergencyAlertsCheckBox != null) { 855 mEmergencyAlertsCheckBox.setEnabled(alertsEnabled); 856 mEmergencyAlertsCheckBox.setChecked( 857 resetCarrierDefault ? alertsEnabled && res.getBoolean( 858 R.bool.emergency_alerts_enabled_default) : alertsEnabled); 859 } 860 if (mPublicSafetyMessagesChannelCheckBox != null) { 861 mPublicSafetyMessagesChannelCheckBox.setEnabled(alertsEnabled); 862 mPublicSafetyMessagesChannelCheckBox.setChecked( 863 resetCarrierDefault ? alertsEnabled && res.getBoolean( 864 R.bool.public_safety_messages_enabled_default) : alertsEnabled); 865 } 866 if (mStateLocalTestCheckBox != null) { 867 mStateLocalTestCheckBox.setEnabled(alertsEnabled); 868 mStateLocalTestCheckBox.setChecked( 869 resetCarrierDefault ? alertsEnabled && res.getBoolean( 870 R.bool.state_local_test_alerts_enabled_default) : alertsEnabled); 871 } 872 if (mTestCheckBox != null) { 873 mTestCheckBox.setEnabled(alertsEnabled); 874 mTestCheckBox.setChecked(resetCarrierDefault ? alertsEnabled && res.getBoolean( 875 R.bool.test_alerts_enabled_default) : alertsEnabled); 876 } 877 if (mExerciseTestCheckBox != null) { 878 mExerciseTestCheckBox.setEnabled(alertsEnabled); 879 mExerciseTestCheckBox.setChecked( 880 resetCarrierDefault ? alertsEnabled && res.getBoolean( 881 R.bool.test_exercise_alerts_enabled_default) : alertsEnabled); 882 } 883 if (mOperatorDefinedCheckBox != null) { 884 mOperatorDefinedCheckBox.setEnabled(alertsEnabled); 885 mOperatorDefinedCheckBox.setChecked( 886 resetCarrierDefault ? alertsEnabled && res.getBoolean( 887 R.bool.test_operator_defined_alerts_enabled_default) 888 : alertsEnabled); 889 } 890 } 891 notifyAreaInfoUpdate(boolean enabled)892 private void notifyAreaInfoUpdate(boolean enabled) { 893 Intent areaInfoIntent = new Intent(AREA_INFO_UPDATE_ACTION); 894 areaInfoIntent.putExtra(AREA_INFO_UPDATE_ENABLED_EXTRA, enabled); 895 // sending broadcast protected by the permission which is only 896 // granted for CBR mainline module. 897 getContext().sendBroadcast(areaInfoIntent, CBR_MODULE_PERMISSION); 898 } 899 900 901 @Override onResume()902 public void onResume() { 903 super.onResume(); 904 updatePreferenceVisibility(); 905 } 906 907 @Override onDestroy()908 public void onDestroy() { 909 super.onDestroy(); 910 LocalBroadcastManager.getInstance(getContext()) 911 .unregisterReceiver(mTestingModeChangedReceiver); 912 } 913 914 /** 915 * Callback to be called when preference or master toggle is changed by user 916 * 917 * @param context Context to use 918 */ onPreferenceChangedByUser(Context context, boolean enableChannels)919 public void onPreferenceChangedByUser(Context context, boolean enableChannels) { 920 if (enableChannels) { 921 Log.d(TAG, "onPreferenceChangedByUser: enable channels"); 922 CellBroadcastReceiver.startConfigService(context, 923 CellBroadcastConfigService.ACTION_ENABLE_CHANNELS); 924 } 925 setPreferenceChanged(context, true); 926 // Notify backup manager a backup pass is needed. 927 new BackupManager(context).dataChanged(); 928 } 929 } 930 931 /** 932 * Check whether vibration toggle is visible 933 * @param context Context 934 * @param res resources 935 */ isVibrationToggleVisible(Context context, Resources res)936 public static boolean isVibrationToggleVisible(Context context, Resources res) { 937 Vibrator vibrator = context.getSystemService(Vibrator.class); 938 boolean supportVibration = (vibrator != null) && vibrator.hasVibrator(); 939 boolean isVibrationToggleVisible = supportVibration 940 && (res.getBoolean(R.bool.show_override_dnd_settings) 941 || !res.getBoolean(R.bool.override_dnd)); 942 return isVibrationToggleVisible; 943 } 944 945 /** 946 * Check whether show full screen message toggle is visible 947 * 948 * @param context Context 949 * @param res resources 950 * @return {@code true} if it needs to show, {@code false} otherwise 951 */ isShowFullScreenMessageVisible(Context context, Resources res)952 public static boolean isShowFullScreenMessageVisible(Context context, Resources res) { 953 // The settings should be based on the config by the subscription 954 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( 955 context, SubscriptionManager.getDefaultSubscriptionId(), null); 956 957 if (res.getBoolean(R.bool.show_public_safety_settings) 958 && !channelManager.getCellBroadcastChannelRanges( 959 R.array.public_safety_messages_channels_range_strings).isEmpty() 960 && res.getBoolean(R.bool.show_public_safety_full_screen_settings)) { 961 Log.d(TAG, "isShowFullScreenMessageVisible : true"); 962 return true; 963 } 964 Log.d(TAG, "isShowFullScreenMessageVisible : false"); 965 return false; 966 } 967 968 /** 969 * Check whether exercise test alert toggle is visible 970 * @param res Resources 971 * @param context Context 972 * @param channelManager ChannelManager 973 */ isExerciseTestAlertsToggleVisible(Resources res, Context context, CellBroadcastChannelManager channelManager)974 public static boolean isExerciseTestAlertsToggleVisible(Resources res, Context context, 975 CellBroadcastChannelManager channelManager) { 976 return res.getBoolean(R.bool.show_separate_exercise_settings) 977 && (res.getBoolean(R.bool.show_exercise_settings) 978 || CellBroadcastReceiver.isTestingMode(context)) 979 && !channelManager.getCellBroadcastChannelRanges( 980 R.array.exercise_alert_range_strings).isEmpty(); 981 } 982 983 /** 984 * Check whether operator test alert toggle is visible 985 * @param res Resources 986 * @param context Context 987 * @param channelManager ChannelManager 988 */ isOperatorTestAlertsToggleVisible(Resources res, Context context, CellBroadcastChannelManager channelManager)989 public static boolean isOperatorTestAlertsToggleVisible(Resources res, Context context, 990 CellBroadcastChannelManager channelManager) { 991 return res.getBoolean(R.bool.show_separate_operator_defined_settings) 992 && (res.getBoolean(R.bool.show_operator_defined_settings) 993 || CellBroadcastReceiver.isTestingMode(context)) 994 && !channelManager.getCellBroadcastChannelRanges( 995 R.array.operator_defined_alert_range_strings).isEmpty(); 996 } 997 isTestAlertsToggleVisible(Context context)998 public static boolean isTestAlertsToggleVisible(Context context) { 999 return isTestAlertsToggleVisible(context, null); 1000 } 1001 1002 /** 1003 * Check whether test alert toggle is visible 1004 * @param context Context 1005 * @param operator Opeator numeric 1006 */ isTestAlertsToggleVisible(Context context, String operator)1007 public static boolean isTestAlertsToggleVisible(Context context, String operator) { 1008 CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(context, 1009 SubscriptionManager.getDefaultSubscriptionId(), operator); 1010 Resources res = operator == null ? getResourcesForDefaultSubId(context) 1011 : getResourcesByOperator(context, 1012 SubscriptionManager.getDefaultSubscriptionId(), operator); 1013 boolean isTestAlertsAvailable = !channelManager.getCellBroadcastChannelRanges( 1014 R.array.required_monthly_test_range_strings).isEmpty() 1015 || (!channelManager.getCellBroadcastChannelRanges( 1016 R.array.exercise_alert_range_strings).isEmpty() 1017 /** exercise toggle is controlled under the main test toggle */ 1018 && (!res.getBoolean(R.bool.show_separate_exercise_settings))) 1019 || (!channelManager.getCellBroadcastChannelRanges( 1020 R.array.operator_defined_alert_range_strings).isEmpty() 1021 /** operator defined toggle is controlled under the main test toggle */ 1022 && (!res.getBoolean(R.bool.show_separate_operator_defined_settings))) 1023 || !channelManager.getCellBroadcastChannelRanges( 1024 R.array.etws_test_alerts_range_strings).isEmpty(); 1025 1026 return (res.getBoolean(R.bool.show_test_settings) 1027 || CellBroadcastReceiver.isTestingMode(context)) 1028 && isTestAlertsAvailable; 1029 } 1030 1031 /** 1032 * Get the device resource based on SIM 1033 * 1034 * @param context Context 1035 * @param subId Subscription index 1036 * 1037 * @return The resource 1038 */ getResources(@onNull Context context, int subId)1039 public static @NonNull Resources getResources(@NonNull Context context, int subId) { 1040 1041 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID 1042 || !SubscriptionManager.isValidSubscriptionId(subId)) { 1043 return context.getResources(); 1044 } 1045 1046 return SubscriptionManager.getResourcesForSubId(context, subId); 1047 } 1048 1049 /** 1050 * Get the resources using the default subscription ID. 1051 * @param context Context 1052 * @return the Resources for the default subscription ID, or if there is no default subscription 1053 * from SubscriptionManager, the resources for the latest loaded SIM. 1054 */ getResourcesForDefaultSubId(@onNull Context context)1055 public static @NonNull Resources getResourcesForDefaultSubId(@NonNull Context context) { 1056 return getResources(context, SubscriptionManager.getDefaultSubscriptionId()); 1057 } 1058 1059 /** 1060 * Get the resources per network operator 1061 * @param context Context 1062 * @param operator Opeator numeric 1063 * @return the Resources based on network operator 1064 */ getResourcesByOperator( @onNull Context context, int subId, @NonNull String operator)1065 public static @NonNull Resources getResourcesByOperator( 1066 @NonNull Context context, int subId, @NonNull String operator) { 1067 if (operator == null || operator.isEmpty()) { 1068 return getResources(context, subId); 1069 } 1070 1071 synchronized (sCacheLock) { 1072 Resources res = sResourcesCacheByOperator.get(operator); 1073 if (res != null) { 1074 return res; 1075 } 1076 1077 Configuration overrideConfig = new Configuration(); 1078 try { 1079 int mcc = Integer.parseInt(operator.substring(0, 3)); 1080 int mnc = operator.length() > 3 ? Integer.parseInt(operator.substring(3)) 1081 : Configuration.MNC_ZERO; 1082 1083 overrideConfig.mcc = mcc; 1084 overrideConfig.mnc = mnc; 1085 } catch (NumberFormatException e) { 1086 // should not happen 1087 Log.e(TAG, "invalid operator: " + operator); 1088 return context.getResources(); 1089 } 1090 1091 Context newContext = context.createConfigurationContext(overrideConfig); 1092 res = newContext.getResources(); 1093 1094 sResourcesCacheByOperator.put(operator, res); 1095 return res; 1096 } 1097 } 1098 1099 /** 1100 * Get the resources id which is used for the default value of the preference 1101 * @param key the preference key 1102 * @return a valid resources id if the key is valid and the default value is 1103 * defined, otherwise 0 1104 */ getResourcesIdForDefaultPrefValue(String key)1105 public static int getResourcesIdForDefaultPrefValue(String key) { 1106 switch (key) { 1107 case KEY_ENABLE_ALERTS_MASTER_TOGGLE: 1108 return R.bool.master_toggle_enabled_default; 1109 case KEY_ENABLE_PUBLIC_SAFETY_MESSAGES: 1110 return R.bool.public_safety_messages_enabled_default; 1111 case KEY_ENABLE_PUBLIC_SAFETY_MESSAGES_FULL_SCREEN: 1112 return R.bool.public_safety_messages_full_screen_enabled_default; 1113 case KEY_ENABLE_EMERGENCY_ALERTS: 1114 return R.bool.emergency_alerts_enabled_default; 1115 case KEY_ENABLE_ALERT_SPEECH: 1116 return R.bool.enable_alert_speech_default; 1117 case KEY_OVERRIDE_DND: 1118 return R.bool.override_dnd_default; 1119 case KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS: 1120 return R.bool.extreme_threat_alerts_enabled_default; 1121 case KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS: 1122 return R.bool.severe_threat_alerts_enabled_default; 1123 case KEY_ENABLE_CMAS_AMBER_ALERTS: 1124 return R.bool.amber_alerts_enabled_default; 1125 case KEY_ENABLE_TEST_ALERTS: 1126 return R.bool.test_alerts_enabled_default; 1127 case KEY_ENABLE_EXERCISE_ALERTS: 1128 return R.bool.test_exercise_alerts_enabled_default; 1129 case KEY_OPERATOR_DEFINED_ALERTS: 1130 return R.bool.test_operator_defined_alerts_enabled_default; 1131 case KEY_ENABLE_STATE_LOCAL_TEST_ALERTS: 1132 return R.bool.state_local_test_alerts_enabled_default; 1133 case KEY_ENABLE_AREA_UPDATE_INFO_ALERTS: 1134 return R.bool.area_update_info_alerts_enabled_default; 1135 default: 1136 return 0; 1137 } 1138 } 1139 1140 /** 1141 * Reset the resources cache. 1142 */ 1143 @VisibleForTesting resetResourcesCache()1144 public static void resetResourcesCache() { 1145 synchronized (sCacheLock) { 1146 sResourcesCacheByOperator.clear(); 1147 } 1148 } 1149 } 1150