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.Activity;
22 import android.app.Fragment;
23 import android.app.backup.BackupManager;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.SharedPreferences;
29 import android.content.pm.PackageManager;
30 import android.content.res.Resources;
31 import android.os.Bundle;
32 import android.os.PersistableBundle;
33 import android.os.UserManager;
34 import android.telephony.CarrierConfigManager;
35 import android.telephony.SubscriptionManager;
36 import android.util.Log;
37 import android.view.MenuItem;
38 
39 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
40 import androidx.preference.ListPreference;
41 import androidx.preference.Preference;
42 import androidx.preference.PreferenceCategory;
43 import androidx.preference.PreferenceFragment;
44 import androidx.preference.PreferenceManager;
45 import androidx.preference.PreferenceScreen;
46 import androidx.preference.TwoStatePreference;
47 
48 import com.android.internal.annotations.VisibleForTesting;
49 
50 import java.util.HashMap;
51 import java.util.Map;
52 
53 /**
54  * Settings activity for the cell broadcast receiver.
55  */
56 public class CellBroadcastSettings extends Activity {
57 
58     private static final String TAG = "CellBroadcastSettings";
59 
60     private static final boolean DBG = false;
61 
62     // Preference key for alert header (A text view, not clickable).
63     public static final String KEY_ALERTS_HEADER = "alerts_header";
64 
65     // Preference key for a main toggle to enable/disable all alerts message (default enabled).
66     public static final String KEY_ENABLE_ALERTS_MASTER_TOGGLE = "enable_alerts_master_toggle";
67 
68     // Preference key for whether to enable public safety messages (default enabled).
69     public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES = "enable_public_safety_messages";
70 
71     // Preference key for whether to enable emergency alerts (default enabled).
72     public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts";
73 
74     // Enable vibration on alert (unless main volume is silent).
75     public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate";
76 
77     // Play alert sound in full volume regardless Do Not Disturb is on.
78     public static final String KEY_OVERRIDE_DND = "override_dnd";
79 
80     public static final String KEY_OVERRIDE_DND_SETTINGS_CHANGED =
81             "override_dnd_settings_changed";
82 
83     // Preference category for emergency alert and CMAS settings.
84     public static final String KEY_CATEGORY_EMERGENCY_ALERTS = "category_emergency_alerts";
85 
86     // Preference category for alert preferences.
87     public static final String KEY_CATEGORY_ALERT_PREFERENCES = "category_alert_preferences";
88 
89     // Show checkbox for Presidential alerts in settings
90     // Whether to display CMAS presidential alert notifications (always enabled).
91     public static final String KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS =
92             "enable_cmas_presidential_alerts";
93 
94     // Whether to display CMAS extreme threat notifications (default is enabled).
95     public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS =
96             "enable_cmas_extreme_threat_alerts";
97 
98     // Whether to display CMAS severe threat notifications (default is enabled).
99     public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS =
100             "enable_cmas_severe_threat_alerts";
101 
102     // Whether to display CMAS amber alert messages (default is enabled).
103     public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts";
104 
105     // Whether to display monthly test messages (default is disabled).
106     public static final String KEY_ENABLE_TEST_ALERTS = "enable_test_alerts";
107 
108     // Whether to display state/local test messages (default disabled).
109     public static final String KEY_ENABLE_STATE_LOCAL_TEST_ALERTS =
110             "enable_state_local_test_alerts";
111 
112     // Preference key for whether to enable area update information notifications
113     // Enabled by default for phones sold in Brazil and India, otherwise this setting may be hidden.
114     public static final String KEY_ENABLE_AREA_UPDATE_INFO_ALERTS =
115             "enable_area_update_info_alerts";
116 
117     // Preference key for initial opt-in/opt-out dialog.
118     public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
119 
120     // Alert reminder interval ("once" = single 2 minute reminder).
121     public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
122 
123     // Preference key for emergency alerts history
124     public static final String KEY_EMERGENCY_ALERT_HISTORY = "emergency_alert_history";
125 
126     // For watch layout
127     private static final String KEY_WATCH_ALERT_REMINDER = "watch_alert_reminder";
128 
129     // Resource cache
130     private static final Map<Integer, Resources> sResourcesCache = new HashMap<>();
131 
132     // Test override for disabling the subId specific resources
133     private static boolean sUseResourcesForSubId = true;
134 
135     // Whether to receive alert in second language code
136     public static final String KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE =
137             "receive_cmas_in_second_language";
138 
139     @Override
onCreate(Bundle savedInstanceState)140     public void onCreate(Bundle savedInstanceState) {
141         super.onCreate(savedInstanceState);
142 
143         ActionBar actionBar = getActionBar();
144         if (actionBar != null) {
145             // android.R.id.home will be triggered in onOptionsItemSelected()
146             actionBar.setDisplayHomeAsUpEnabled(true);
147         }
148 
149         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
150         if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) {
151             setContentView(R.layout.cell_broadcast_disallowed_preference_screen);
152             return;
153         }
154 
155         // We only add new CellBroadcastSettingsFragment if no fragment is restored.
156         Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content);
157         if (fragment == null) {
158             fragment = new CellBroadcastSettingsFragment();
159             getFragmentManager()
160                     .beginTransaction()
161                     .add(android.R.id.content, fragment)
162                     .commit();
163         }
164     }
165 
166     @Override
onOptionsItemSelected(MenuItem item)167     public boolean onOptionsItemSelected(MenuItem item) {
168         switch (item.getItemId()) {
169             // Respond to the action bar's Up/Home button
170             case android.R.id.home:
171                 finish();
172                 return true;
173         }
174         return super.onOptionsItemSelected(item);
175     }
176 
177     /**
178      * New fragment-style implementation of preferences.
179      */
180     public static class CellBroadcastSettingsFragment extends PreferenceFragment {
181 
182         private TwoStatePreference mExtremeCheckBox;
183         private TwoStatePreference mSevereCheckBox;
184         private TwoStatePreference mAmberCheckBox;
185         private TwoStatePreference mMasterToggle;
186         private TwoStatePreference mPublicSafetyMessagesChannelCheckBox;
187         private TwoStatePreference mEmergencyAlertsCheckBox;
188         private ListPreference mReminderInterval;
189         private TwoStatePreference mOverrideDndCheckBox;
190         private TwoStatePreference mAreaUpdateInfoCheckBox;
191         private TwoStatePreference mTestCheckBox;
192         private TwoStatePreference mStateLocalTestCheckBox;
193         private TwoStatePreference mEnableVibrateCheckBox;
194         private Preference mAlertHistory;
195         private Preference mAlertsHeader;
196         private PreferenceCategory mAlertCategory;
197         private PreferenceCategory mAlertPreferencesCategory;
198         private boolean mDisableSevereWhenExtremeDisabled = true;
199 
200         // WATCH
201         private TwoStatePreference mAlertReminder;
202 
203         // Show checkbox for Presidential alerts in settings
204         private TwoStatePreference mPresidentialCheckBox;
205 
206         // on/off switch in settings for receiving alert in second language code
207         private TwoStatePreference mReceiveCmasInSecondLanguageCheckBox;
208 
209         private final BroadcastReceiver mTestingModeChangedReeiver = new BroadcastReceiver() {
210             @Override
211             public void onReceive(Context context, Intent intent) {
212                 switch (intent.getAction()) {
213                     case CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED:
214                         updatePreferenceVisibility();
215                         break;
216                 }
217             }
218         };
219 
220         @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)221         public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
222 
223             LocalBroadcastManager.getInstance(getContext())
224                     .registerReceiver(mTestingModeChangedReeiver, new IntentFilter(
225                             CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED));
226 
227             // Load the preferences from an XML resource
228             PackageManager pm = getActivity().getPackageManager();
229             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
230                 addPreferencesFromResource(R.xml.watch_preferences);
231             } else {
232                 addPreferencesFromResource(R.xml.preferences);
233             }
234 
235             PreferenceScreen preferenceScreen = getPreferenceScreen();
236 
237             mExtremeCheckBox = (TwoStatePreference)
238                     findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS);
239             mSevereCheckBox = (TwoStatePreference)
240                     findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS);
241             mAmberCheckBox = (TwoStatePreference)
242                     findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS);
243             mMasterToggle = (TwoStatePreference)
244                     findPreference(KEY_ENABLE_ALERTS_MASTER_TOGGLE);
245             mPublicSafetyMessagesChannelCheckBox = (TwoStatePreference)
246                     findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES);
247             mEmergencyAlertsCheckBox = (TwoStatePreference)
248                     findPreference(KEY_ENABLE_EMERGENCY_ALERTS);
249             mReminderInterval = (ListPreference)
250                     findPreference(KEY_ALERT_REMINDER_INTERVAL);
251             mOverrideDndCheckBox = (TwoStatePreference)
252                     findPreference(KEY_OVERRIDE_DND);
253             mAreaUpdateInfoCheckBox = (TwoStatePreference)
254                     findPreference(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS);
255             mTestCheckBox = (TwoStatePreference)
256                     findPreference(KEY_ENABLE_TEST_ALERTS);
257             mStateLocalTestCheckBox = (TwoStatePreference)
258                     findPreference(KEY_ENABLE_STATE_LOCAL_TEST_ALERTS);
259             mAlertHistory = findPreference(KEY_EMERGENCY_ALERT_HISTORY);
260             mAlertsHeader = findPreference(KEY_ALERTS_HEADER);
261             mReceiveCmasInSecondLanguageCheckBox = (TwoStatePreference) findPreference
262                     (KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE);
263             mEnableVibrateCheckBox = findPreference(KEY_ENABLE_ALERT_VIBRATE);
264 
265             // Show checkbox for Presidential alerts in settings
266             mPresidentialCheckBox = (TwoStatePreference)
267                     findPreference(KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS);
268 
269             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
270                 mAlertReminder = (TwoStatePreference)
271                         findPreference(KEY_WATCH_ALERT_REMINDER);
272                 if (Integer.valueOf(mReminderInterval.getValue()) == 0) {
273                     mAlertReminder.setChecked(false);
274                 } else {
275                     mAlertReminder.setChecked(true);
276                 }
277                 mAlertReminder.setOnPreferenceChangeListener((p, newVal) -> {
278                     try {
279                         mReminderInterval.setValueIndex((Boolean) newVal ? 1 : 3);
280                     } catch (IndexOutOfBoundsException e) {
281                         mReminderInterval.setValue(String.valueOf(0));
282                         Log.w(TAG, "Setting default value");
283                     }
284                     return true;
285                 });
286                 PreferenceScreen watchScreen = (PreferenceScreen)
287                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
288                 watchScreen.removePreference(mReminderInterval);
289             } else {
290                 mAlertPreferencesCategory = (PreferenceCategory)
291                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
292                 mAlertCategory = (PreferenceCategory)
293                         findPreference(KEY_CATEGORY_EMERGENCY_ALERTS);
294             }
295 
296             Resources res = CellBroadcastSettings.getResources(getContext(),
297                     SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
298 
299             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
300             mDisableSevereWhenExtremeDisabled = res.getBoolean(
301                     R.bool.disable_severe_when_extreme_disabled);
302 
303             // Handler for settings that require us to reconfigure enabled channels in radio
304             Preference.OnPreferenceChangeListener startConfigServiceListener =
305                     new Preference.OnPreferenceChangeListener() {
306                         @Override
307                         public boolean onPreferenceChange(Preference pref, Object newValue) {
308                             CellBroadcastReceiver.startConfigService(pref.getContext());
309 
310                             if (mDisableSevereWhenExtremeDisabled) {
311                                 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) {
312                                     boolean isExtremeAlertChecked = (Boolean) newValue;
313                                     if (mSevereCheckBox != null) {
314                                         mSevereCheckBox.setEnabled(isExtremeAlertChecked);
315                                         mSevereCheckBox.setChecked(false);
316                                     }
317                                 }
318                             }
319 
320                             if (pref.getKey().equals(KEY_ENABLE_ALERTS_MASTER_TOGGLE)) {
321                                 boolean isEnableAlerts = (Boolean) newValue;
322                                 setAlertsEnabled(isEnableAlerts);
323                             }
324 
325                             // Notify backup manager a backup pass is needed.
326                             new BackupManager(getContext()).dataChanged();
327                             return true;
328                         }
329                     };
330 
331             initReminderIntervalList();
332 
333             if (mMasterToggle != null) {
334                 mMasterToggle.setOnPreferenceChangeListener(startConfigServiceListener);
335                 // If allow alerts are disabled, we turn all sub-alerts off. If it's enabled, we
336                 // leave them as they are.
337                 if (!mMasterToggle.isChecked()) {
338                     setAlertsEnabled(false);
339                 }
340             }
341 
342             if (mAreaUpdateInfoCheckBox != null) {
343                 mAreaUpdateInfoCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
344             }
345             if (mExtremeCheckBox != null) {
346                 mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
347             }
348             if (mPublicSafetyMessagesChannelCheckBox != null) {
349                 mPublicSafetyMessagesChannelCheckBox.setOnPreferenceChangeListener(
350                         startConfigServiceListener);
351             }
352             if (mEmergencyAlertsCheckBox != null) {
353                 mEmergencyAlertsCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
354             }
355             if (mSevereCheckBox != null) {
356                 mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
357                 if (mDisableSevereWhenExtremeDisabled) {
358                     if (mExtremeCheckBox != null) {
359                         mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked());
360                     }
361                 }
362             }
363             if (mAmberCheckBox != null) {
364                 mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
365             }
366             if (mTestCheckBox != null) {
367                 mTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
368             }
369             if (mStateLocalTestCheckBox != null) {
370                 mStateLocalTestCheckBox.setOnPreferenceChangeListener(
371                         startConfigServiceListener);
372             }
373 
374             if (mOverrideDndCheckBox != null) {
375                 if (!sp.getBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED, false)) {
376                     // If the user hasn't changed this settings yet, use the default settings
377                     // from resource overlay.
378                     mOverrideDndCheckBox.setChecked(res.getBoolean(R.bool.override_dnd_default));
379                 }
380                 mOverrideDndCheckBox.setOnPreferenceChangeListener(
381                         (pref, newValue) -> {
382                             sp.edit().putBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED,
383                                     true).apply();
384                             updateVibrationPreference((boolean) newValue);
385                             return true;
386                         });
387             }
388 
389             if (mAlertHistory != null) {
390                 mAlertHistory.setOnPreferenceClickListener(
391                         preference -> {
392                             final Intent intent = new Intent(getContext(),
393                                     CellBroadcastListActivity.class);
394                             startActivity(intent);
395                             return true;
396                         });
397             }
398 
399             updateVibrationPreference(sp.getBoolean(CellBroadcastSettings.KEY_OVERRIDE_DND,
400                     false));
401             updatePreferenceVisibility();
402         }
403 
404         /**
405          * Update the vibration preference based on override DND. If DND is overridden, then do
406          * not allow users to turn off vibration.
407          *
408          * @param overrideDnd {@code true} if the alert will be played at full volume, regardless
409          * DND settings.
410          */
updateVibrationPreference(boolean overrideDnd)411         private void updateVibrationPreference(boolean overrideDnd) {
412             if (mEnableVibrateCheckBox != null) {
413                 if (overrideDnd) {
414                     // If DND is enabled, always enable vibration.
415                     mEnableVibrateCheckBox.setChecked(true);
416                 }
417                 // Grey out the preference if DND is overridden.
418                 mEnableVibrateCheckBox.setEnabled(!overrideDnd);
419             }
420         }
421 
422         /**
423          * Dynamically update each preference's visibility based on configuration.
424          */
updatePreferenceVisibility()425         private void updatePreferenceVisibility() {
426             Resources res = CellBroadcastSettings.getResources(getContext(),
427                     SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
428 
429             CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
430                     getContext(), SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
431 
432             if (mPresidentialCheckBox != null) {
433                 mPresidentialCheckBox.setVisible(
434                         res.getBoolean(R.bool.show_presidential_alerts_settings));
435             }
436 
437             if (mExtremeCheckBox != null) {
438                 mExtremeCheckBox.setVisible(res.getBoolean(R.bool.show_extreme_alert_settings)
439                         && !channelManager.getCellBroadcastChannelRanges(
440                                 R.array.cmas_alert_extreme_channels_range_strings).isEmpty());
441             }
442 
443             if (mSevereCheckBox != null) {
444                 mSevereCheckBox.setVisible(res.getBoolean(R.bool.show_severe_alert_settings)
445                         && !channelManager.getCellBroadcastChannelRanges(
446                                 R.array.cmas_alerts_severe_range_strings).isEmpty());
447             }
448 
449             if (mAmberCheckBox != null) {
450                 mAmberCheckBox.setVisible(res.getBoolean(R.bool.show_amber_alert_settings)
451                         && !channelManager.getCellBroadcastChannelRanges(
452                                 R.array.cmas_amber_alerts_channels_range_strings).isEmpty());
453             }
454 
455             if (mPublicSafetyMessagesChannelCheckBox != null) {
456                 mPublicSafetyMessagesChannelCheckBox.setVisible(
457                         res.getBoolean(R.bool.show_public_safety_settings)
458                                 && !channelManager.getCellBroadcastChannelRanges(
459                                         R.array.public_safety_messages_channels_range_strings)
460                                 .isEmpty());
461             }
462 
463             if (mTestCheckBox != null) {
464                 mTestCheckBox.setVisible(isTestAlertsToggleVisible(getContext()));
465             }
466 
467             if (mEmergencyAlertsCheckBox != null) {
468                 mEmergencyAlertsCheckBox.setVisible(!channelManager.getCellBroadcastChannelRanges(
469                         R.array.emergency_alerts_channels_range_strings).isEmpty());
470             }
471 
472             if (mStateLocalTestCheckBox != null) {
473                 mStateLocalTestCheckBox.setVisible(
474                         res.getBoolean(R.bool.show_state_local_test_settings)
475                                 && !channelManager.getCellBroadcastChannelRanges(
476                                         R.array.state_local_test_alert_range_strings).isEmpty());
477             }
478 
479             if (mReceiveCmasInSecondLanguageCheckBox != null) {
480                 mReceiveCmasInSecondLanguageCheckBox.setVisible(!res.getString(
481                         R.string.emergency_alert_second_language_code).isEmpty());
482             }
483 
484             if (mAreaUpdateInfoCheckBox != null) {
485                 mAreaUpdateInfoCheckBox.setVisible(
486                         res.getBoolean(R.bool.config_showAreaUpdateInfoSettings));
487             }
488 
489             if (mOverrideDndCheckBox != null) {
490                 mOverrideDndCheckBox.setVisible(res.getBoolean(R.bool.show_override_dnd_settings));
491             }
492 
493             if (mEnableVibrateCheckBox != null) {
494                 // Only show vibrate toggle when override DND toggle is available to users, or when
495                 // override DND default is turned off.
496                 // In some countries, override DND is always on, which means vibration is always on.
497                 // In that case, no need to show vibration toggle for users.
498                 mEnableVibrateCheckBox.setVisible(
499                         res.getBoolean(R.bool.show_override_dnd_settings)
500                                 || !res.getBoolean(R.bool.override_dnd_default));
501             }
502             if (mAlertsHeader != null) {
503                 mAlertsHeader.setVisible(
504                         !getContext().getString(R.string.alerts_header_summary).isEmpty());
505             }
506         }
507 
initReminderIntervalList()508         private void initReminderIntervalList() {
509             Resources res = CellBroadcastSettings.getResources(
510                     getContext(), SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
511 
512             String[] activeValues =
513                     res.getStringArray(R.array.alert_reminder_interval_active_values);
514             String[] allEntries = res.getStringArray(R.array.alert_reminder_interval_entries);
515             String[] newEntries = new String[activeValues.length];
516 
517             // Only add active interval to the list
518             for (int i = 0; i < activeValues.length; i++) {
519                 int index = mReminderInterval.findIndexOfValue(activeValues[i]);
520                 if (index != -1) {
521                     newEntries[i] = allEntries[index];
522                     if (DBG) Log.d(TAG, "Added " + allEntries[index]);
523                 } else {
524                     Log.e(TAG, "Can't find " + activeValues[i]);
525                 }
526             }
527 
528             mReminderInterval.setEntries(newEntries);
529             mReminderInterval.setEntryValues(activeValues);
530             mReminderInterval.setSummary(mReminderInterval.getEntry());
531             mReminderInterval.setOnPreferenceChangeListener(
532                     new Preference.OnPreferenceChangeListener() {
533                         @Override
534                         public boolean onPreferenceChange(Preference pref, Object newValue) {
535                             final ListPreference listPref = (ListPreference) pref;
536                             final int idx = listPref.findIndexOfValue((String) newValue);
537                             listPref.setSummary(listPref.getEntries()[idx]);
538                             return true;
539                         }
540                     });
541         }
542 
543 
setAlertsEnabled(boolean alertsEnabled)544         private void setAlertsEnabled(boolean alertsEnabled) {
545             if (mSevereCheckBox != null) {
546                 mSevereCheckBox.setEnabled(alertsEnabled);
547                 mSevereCheckBox.setChecked(alertsEnabled);
548             }
549             if (mExtremeCheckBox != null) {
550                 mExtremeCheckBox.setEnabled(alertsEnabled);
551                 mExtremeCheckBox.setChecked(alertsEnabled);
552             }
553             if (mAmberCheckBox != null) {
554                 mAmberCheckBox.setEnabled(alertsEnabled);
555                 mAmberCheckBox.setChecked(alertsEnabled);
556             }
557             if (mAreaUpdateInfoCheckBox != null) {
558                 mAreaUpdateInfoCheckBox.setEnabled(alertsEnabled);
559                 mAreaUpdateInfoCheckBox.setChecked(alertsEnabled);
560             }
561             if (mAlertPreferencesCategory != null) {
562                 mAlertPreferencesCategory.setEnabled(alertsEnabled);
563             }
564             if (mEmergencyAlertsCheckBox != null) {
565                 mEmergencyAlertsCheckBox.setEnabled(alertsEnabled);
566                 mEmergencyAlertsCheckBox.setChecked(alertsEnabled);
567             }
568             if (mPublicSafetyMessagesChannelCheckBox != null) {
569                 mPublicSafetyMessagesChannelCheckBox.setEnabled(alertsEnabled);
570                 mPublicSafetyMessagesChannelCheckBox.setChecked(alertsEnabled);
571             }
572             if (mStateLocalTestCheckBox != null) {
573                 mStateLocalTestCheckBox.setEnabled(alertsEnabled);
574                 mStateLocalTestCheckBox.setChecked(alertsEnabled);
575             }
576             if (mTestCheckBox != null) {
577                 mTestCheckBox.setEnabled(alertsEnabled);
578                 mTestCheckBox.setChecked(alertsEnabled);
579             }
580         }
581 
582         @Override
onResume()583         public void onResume() {
584             super.onResume();
585             updatePreferenceVisibility();
586         }
587 
588         @Override
onDestroy()589         public void onDestroy() {
590             super.onDestroy();
591             LocalBroadcastManager.getInstance(getContext())
592                     .unregisterReceiver(mTestingModeChangedReeiver);
593         }
594     }
595 
isTestAlertsToggleVisible(Context context)596     public static boolean isTestAlertsToggleVisible(Context context) {
597         CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(context,
598                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
599         Resources res = CellBroadcastSettings.getResources(context,
600                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
601         boolean isTestAlertsAvailable = !channelManager.getCellBroadcastChannelRanges(
602                 R.array.required_monthly_test_range_strings).isEmpty()
603                 || !channelManager.getCellBroadcastChannelRanges(
604                 R.array.exercise_alert_range_strings).isEmpty()
605                 || !channelManager.getCellBroadcastChannelRanges(
606                 R.array.operator_defined_alert_range_strings).isEmpty()
607                 || !channelManager.getCellBroadcastChannelRanges(
608                 R.array.etws_test_alerts_range_strings).isEmpty();
609 
610         return (res.getBoolean(R.bool.show_test_settings)
611                 || CellBroadcastReceiver.isTestingMode(context))
612                 && isTestAlertsAvailable;
613     }
614 
isFeatureEnabled(Context context, String feature, boolean defaultValue)615     public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) {
616         CarrierConfigManager configManager =
617                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
618 
619         if (configManager != null) {
620             PersistableBundle carrierConfig = configManager.getConfig();
621             if (carrierConfig != null) {
622                 return carrierConfig.getBoolean(feature, defaultValue);
623             }
624         }
625 
626         return defaultValue;
627     }
628 
629     /**
630      * Override used by tests so that we don't call
631      * SubscriptionManager.getResourcesForSubId, which is a static unmockable
632      * method.
633      */
634     @VisibleForTesting
setUseResourcesForSubId(boolean useResourcesForSubId)635     public static void setUseResourcesForSubId(boolean useResourcesForSubId) {
636         sUseResourcesForSubId = useResourcesForSubId;
637     }
638 
639     /**
640      * Get the device resource based on SIM
641      *
642      * @param context Context
643      * @param subId Subscription index
644      *
645      * @return The resource
646      */
getResources(@onNull Context context, int subId)647     public static @NonNull Resources getResources(@NonNull Context context, int subId) {
648         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID
649                 || !SubscriptionManager.isValidSubscriptionId(subId) || !sUseResourcesForSubId) {
650             return context.getResources();
651         }
652 
653         if (sResourcesCache.containsKey(subId)) {
654             return sResourcesCache.get(subId);
655         }
656 
657         Resources res = SubscriptionManager.getResourcesForSubId(context, subId);
658         sResourcesCache.put(subId, res);
659 
660         return res;
661     }
662 }
663