• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.cellbroadcastreceiver;
18 
19 import android.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