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 master 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 master 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
onStart()167     public void onStart() {
168         super.onStart();
169         getWindow().addSystemFlags(
170                 android.view.WindowManager.LayoutParams
171                         .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
172     }
173 
174     @Override
onOptionsItemSelected(MenuItem item)175     public boolean onOptionsItemSelected(MenuItem item) {
176         switch (item.getItemId()) {
177             // Respond to the action bar's Up/Home button
178             case android.R.id.home:
179                 finish();
180                 return true;
181         }
182         return super.onOptionsItemSelected(item);
183     }
184 
185     /**
186      * New fragment-style implementation of preferences.
187      */
188     public static class CellBroadcastSettingsFragment extends PreferenceFragment {
189 
190         private TwoStatePreference mExtremeCheckBox;
191         private TwoStatePreference mSevereCheckBox;
192         private TwoStatePreference mAmberCheckBox;
193         private TwoStatePreference mMasterToggle;
194         private TwoStatePreference mPublicSafetyMessagesChannelCheckBox;
195         private TwoStatePreference mEmergencyAlertsCheckBox;
196         private ListPreference mReminderInterval;
197         private TwoStatePreference mOverrideDndCheckBox;
198         private TwoStatePreference mAreaUpdateInfoCheckBox;
199         private TwoStatePreference mTestCheckBox;
200         private TwoStatePreference mStateLocalTestCheckBox;
201         private TwoStatePreference mEnableVibrateCheckBox;
202         private Preference mAlertHistory;
203         private Preference mAlertsHeader;
204         private PreferenceCategory mAlertCategory;
205         private PreferenceCategory mAlertPreferencesCategory;
206         private boolean mDisableSevereWhenExtremeDisabled = true;
207 
208         // WATCH
209         private TwoStatePreference mAlertReminder;
210 
211         // Show checkbox for Presidential alerts in settings
212         private TwoStatePreference mPresidentialCheckBox;
213 
214         // on/off switch in settings for receiving alert in second language code
215         private TwoStatePreference mReceiveCmasInSecondLanguageCheckBox;
216 
217         private final BroadcastReceiver mTestingModeChangedReeiver = new BroadcastReceiver() {
218             @Override
219             public void onReceive(Context context, Intent intent) {
220                 switch (intent.getAction()) {
221                     case CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED:
222                         updatePreferenceVisibility();
223                         break;
224                 }
225             }
226         };
227 
228         @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)229         public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
230 
231             LocalBroadcastManager.getInstance(getContext())
232                     .registerReceiver(mTestingModeChangedReeiver, new IntentFilter(
233                             CellBroadcastReceiver.ACTION_TESTING_MODE_CHANGED));
234 
235             // Load the preferences from an XML resource
236             PackageManager pm = getActivity().getPackageManager();
237             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
238                 addPreferencesFromResource(R.xml.watch_preferences);
239             } else {
240                 addPreferencesFromResource(R.xml.preferences);
241             }
242 
243             PreferenceScreen preferenceScreen = getPreferenceScreen();
244 
245             mExtremeCheckBox = (TwoStatePreference)
246                     findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS);
247             mSevereCheckBox = (TwoStatePreference)
248                     findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS);
249             mAmberCheckBox = (TwoStatePreference)
250                     findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS);
251             mMasterToggle = (TwoStatePreference)
252                     findPreference(KEY_ENABLE_ALERTS_MASTER_TOGGLE);
253             mPublicSafetyMessagesChannelCheckBox = (TwoStatePreference)
254                     findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES);
255             mEmergencyAlertsCheckBox = (TwoStatePreference)
256                     findPreference(KEY_ENABLE_EMERGENCY_ALERTS);
257             mReminderInterval = (ListPreference)
258                     findPreference(KEY_ALERT_REMINDER_INTERVAL);
259             mOverrideDndCheckBox = (TwoStatePreference)
260                     findPreference(KEY_OVERRIDE_DND);
261             mAreaUpdateInfoCheckBox = (TwoStatePreference)
262                     findPreference(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS);
263             mTestCheckBox = (TwoStatePreference)
264                     findPreference(KEY_ENABLE_TEST_ALERTS);
265             mStateLocalTestCheckBox = (TwoStatePreference)
266                     findPreference(KEY_ENABLE_STATE_LOCAL_TEST_ALERTS);
267             mAlertHistory = findPreference(KEY_EMERGENCY_ALERT_HISTORY);
268             mAlertsHeader = findPreference(KEY_ALERTS_HEADER);
269             mReceiveCmasInSecondLanguageCheckBox = (TwoStatePreference) findPreference
270                     (KEY_RECEIVE_CMAS_IN_SECOND_LANGUAGE);
271             mEnableVibrateCheckBox = findPreference(KEY_ENABLE_ALERT_VIBRATE);
272 
273             // Show checkbox for Presidential alerts in settings
274             mPresidentialCheckBox = (TwoStatePreference)
275                     findPreference(KEY_ENABLE_CMAS_PRESIDENTIAL_ALERTS);
276 
277             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
278                 mAlertReminder = (TwoStatePreference)
279                         findPreference(KEY_WATCH_ALERT_REMINDER);
280                 if (Integer.valueOf(mReminderInterval.getValue()) == 0) {
281                     mAlertReminder.setChecked(false);
282                 } else {
283                     mAlertReminder.setChecked(true);
284                 }
285                 mAlertReminder.setOnPreferenceChangeListener((p, newVal) -> {
286                     try {
287                         mReminderInterval.setValueIndex((Boolean) newVal ? 1 : 3);
288                     } catch (IndexOutOfBoundsException e) {
289                         mReminderInterval.setValue(String.valueOf(0));
290                         Log.w(TAG, "Setting default value");
291                     }
292                     return true;
293                 });
294                 PreferenceScreen watchScreen = (PreferenceScreen)
295                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
296                 watchScreen.removePreference(mReminderInterval);
297             } else {
298                 mAlertPreferencesCategory = (PreferenceCategory)
299                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
300                 mAlertCategory = (PreferenceCategory)
301                         findPreference(KEY_CATEGORY_EMERGENCY_ALERTS);
302             }
303 
304             Resources res = CellBroadcastSettings.getResources(getContext(),
305                     SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
306 
307             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
308             mDisableSevereWhenExtremeDisabled = res.getBoolean(
309                     R.bool.disable_severe_when_extreme_disabled);
310 
311             // Handler for settings that require us to reconfigure enabled channels in radio
312             Preference.OnPreferenceChangeListener startConfigServiceListener =
313                     new Preference.OnPreferenceChangeListener() {
314                         @Override
315                         public boolean onPreferenceChange(Preference pref, Object newValue) {
316                             CellBroadcastReceiver.startConfigService(pref.getContext());
317 
318                             if (mDisableSevereWhenExtremeDisabled) {
319                                 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) {
320                                     boolean isExtremeAlertChecked = (Boolean) newValue;
321                                     if (mSevereCheckBox != null) {
322                                         mSevereCheckBox.setEnabled(isExtremeAlertChecked);
323                                         mSevereCheckBox.setChecked(false);
324                                     }
325                                 }
326                             }
327 
328                             if (pref.getKey().equals(KEY_ENABLE_ALERTS_MASTER_TOGGLE)) {
329                                 boolean isEnableAlerts = (Boolean) newValue;
330                                 setAlertsEnabled(isEnableAlerts);
331                             }
332 
333                             // Notify backup manager a backup pass is needed.
334                             new BackupManager(getContext()).dataChanged();
335                             return true;
336                         }
337                     };
338 
339             initReminderIntervalList();
340 
341             if (mMasterToggle != null) {
342                 mMasterToggle.setOnPreferenceChangeListener(startConfigServiceListener);
343                 // If allow alerts are disabled, we turn all sub-alerts off. If it's enabled, we
344                 // leave them as they are.
345                 if (!mMasterToggle.isChecked()) {
346                     setAlertsEnabled(false);
347                 }
348             }
349 
350             if (mAreaUpdateInfoCheckBox != null) {
351                 mAreaUpdateInfoCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
352             }
353             if (mExtremeCheckBox != null) {
354                 mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
355             }
356             if (mPublicSafetyMessagesChannelCheckBox != null) {
357                 mPublicSafetyMessagesChannelCheckBox.setOnPreferenceChangeListener(
358                         startConfigServiceListener);
359             }
360             if (mEmergencyAlertsCheckBox != null) {
361                 mEmergencyAlertsCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
362             }
363             if (mSevereCheckBox != null) {
364                 mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
365                 if (mDisableSevereWhenExtremeDisabled) {
366                     if (mExtremeCheckBox != null) {
367                         mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked());
368                     }
369                 }
370             }
371             if (mAmberCheckBox != null) {
372                 mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
373             }
374             if (mTestCheckBox != null) {
375                 mTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
376             }
377             if (mStateLocalTestCheckBox != null) {
378                 mStateLocalTestCheckBox.setOnPreferenceChangeListener(
379                         startConfigServiceListener);
380             }
381 
382             if (mOverrideDndCheckBox != null) {
383                 if (!sp.getBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED, false)) {
384                     // If the user hasn't changed this settings yet, use the default settings
385                     // from resource overlay.
386                     mOverrideDndCheckBox.setChecked(res.getBoolean(R.bool.override_dnd_default));
387                 }
388                 mOverrideDndCheckBox.setOnPreferenceChangeListener(
389                         (pref, newValue) -> {
390                             sp.edit().putBoolean(KEY_OVERRIDE_DND_SETTINGS_CHANGED,
391                                     true).apply();
392                             updateVibrationPreference((boolean) newValue);
393                             return true;
394                         });
395             }
396 
397             if (mAlertHistory != null) {
398                 mAlertHistory.setOnPreferenceClickListener(
399                         preference -> {
400                             final Intent intent = new Intent(getContext(),
401                                     CellBroadcastListActivity.class);
402                             startActivity(intent);
403                             return true;
404                         });
405             }
406 
407             updateVibrationPreference(sp.getBoolean(CellBroadcastSettings.KEY_OVERRIDE_DND,
408                     false));
409             updatePreferenceVisibility();
410         }
411 
412         /**
413          * Update the vibration preference based on override DND. If DND is overridden, then do
414          * not allow users to turn off vibration.
415          *
416          * @param overrideDnd {@code true} if the alert will be played at full volume, regardless
417          * DND settings.
418          */
updateVibrationPreference(boolean overrideDnd)419         private void updateVibrationPreference(boolean overrideDnd) {
420             if (mEnableVibrateCheckBox != null) {
421                 if (overrideDnd) {
422                     // If DND is enabled, always enable vibration.
423                     mEnableVibrateCheckBox.setChecked(true);
424                 }
425                 // Grey out the preference if DND is overridden.
426                 mEnableVibrateCheckBox.setEnabled(!overrideDnd);
427             }
428         }
429 
430         /**
431          * Dynamically update each preference's visibility based on configuration.
432          */
updatePreferenceVisibility()433         private void updatePreferenceVisibility() {
434             Resources res = CellBroadcastSettings.getResources(getContext(),
435                     SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
436 
437             CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(
438                     getContext(), SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
439 
440             if (mPresidentialCheckBox != null) {
441                 mPresidentialCheckBox.setVisible(
442                         res.getBoolean(R.bool.show_presidential_alerts_settings));
443             }
444 
445             if (mExtremeCheckBox != null) {
446                 mExtremeCheckBox.setVisible(res.getBoolean(R.bool.show_extreme_alert_settings)
447                         && !channelManager.getCellBroadcastChannelRanges(
448                                 R.array.cmas_alert_extreme_channels_range_strings).isEmpty());
449             }
450 
451             if (mSevereCheckBox != null) {
452                 mSevereCheckBox.setVisible(res.getBoolean(R.bool.show_severe_alert_settings)
453                         && !channelManager.getCellBroadcastChannelRanges(
454                                 R.array.cmas_alerts_severe_range_strings).isEmpty());
455             }
456 
457             if (mAmberCheckBox != null) {
458                 mAmberCheckBox.setVisible(res.getBoolean(R.bool.show_amber_alert_settings)
459                         && !channelManager.getCellBroadcastChannelRanges(
460                                 R.array.cmas_amber_alerts_channels_range_strings).isEmpty());
461             }
462 
463             if (mPublicSafetyMessagesChannelCheckBox != null) {
464                 mPublicSafetyMessagesChannelCheckBox.setVisible(
465                         res.getBoolean(R.bool.show_public_safety_settings)
466                                 && !channelManager.getCellBroadcastChannelRanges(
467                                         R.array.public_safety_messages_channels_range_strings)
468                                 .isEmpty());
469             }
470 
471             if (mTestCheckBox != null) {
472                 mTestCheckBox.setVisible(isTestAlertsToggleVisible(getContext()));
473             }
474 
475             if (mEmergencyAlertsCheckBox != null) {
476                 mEmergencyAlertsCheckBox.setVisible(!channelManager.getCellBroadcastChannelRanges(
477                         R.array.emergency_alerts_channels_range_strings).isEmpty());
478             }
479 
480             if (mStateLocalTestCheckBox != null) {
481                 mStateLocalTestCheckBox.setVisible(
482                         res.getBoolean(R.bool.show_state_local_test_settings)
483                                 && !channelManager.getCellBroadcastChannelRanges(
484                                         R.array.state_local_test_alert_range_strings).isEmpty());
485             }
486 
487             if (mReceiveCmasInSecondLanguageCheckBox != null) {
488                 mReceiveCmasInSecondLanguageCheckBox.setVisible(!res.getString(
489                         R.string.emergency_alert_second_language_code).isEmpty());
490             }
491 
492             if (mAreaUpdateInfoCheckBox != null) {
493                 mAreaUpdateInfoCheckBox.setVisible(
494                         res.getBoolean(R.bool.config_showAreaUpdateInfoSettings));
495             }
496 
497             if (mOverrideDndCheckBox != null) {
498                 mOverrideDndCheckBox.setVisible(res.getBoolean(R.bool.show_override_dnd_settings));
499             }
500 
501             if (mEnableVibrateCheckBox != null) {
502                 // Only show vibrate toggle when override DND toggle is available to users, or when
503                 // override DND default is turned off.
504                 // In some countries, override DND is always on, which means vibration is always on.
505                 // In that case, no need to show vibration toggle for users.
506                 mEnableVibrateCheckBox.setVisible(
507                         res.getBoolean(R.bool.show_override_dnd_settings)
508                                 || !res.getBoolean(R.bool.override_dnd_default));
509             }
510             if (mAlertsHeader != null) {
511                 mAlertsHeader.setVisible(
512                         !getContext().getString(R.string.alerts_header_summary).isEmpty());
513             }
514         }
515 
initReminderIntervalList()516         private void initReminderIntervalList() {
517             Resources res = CellBroadcastSettings.getResources(
518                     getContext(), SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
519 
520             String[] activeValues =
521                     res.getStringArray(R.array.alert_reminder_interval_active_values);
522             String[] allEntries = res.getStringArray(R.array.alert_reminder_interval_entries);
523             String[] newEntries = new String[activeValues.length];
524 
525             // Only add active interval to the list
526             for (int i = 0; i < activeValues.length; i++) {
527                 int index = mReminderInterval.findIndexOfValue(activeValues[i]);
528                 if (index != -1) {
529                     newEntries[i] = allEntries[index];
530                     if (DBG) Log.d(TAG, "Added " + allEntries[index]);
531                 } else {
532                     Log.e(TAG, "Can't find " + activeValues[i]);
533                 }
534             }
535 
536             mReminderInterval.setEntries(newEntries);
537             mReminderInterval.setEntryValues(activeValues);
538             mReminderInterval.setSummary(mReminderInterval.getEntry());
539             mReminderInterval.setOnPreferenceChangeListener(
540                     new Preference.OnPreferenceChangeListener() {
541                         @Override
542                         public boolean onPreferenceChange(Preference pref, Object newValue) {
543                             final ListPreference listPref = (ListPreference) pref;
544                             final int idx = listPref.findIndexOfValue((String) newValue);
545                             listPref.setSummary(listPref.getEntries()[idx]);
546                             return true;
547                         }
548                     });
549         }
550 
551 
setAlertsEnabled(boolean alertsEnabled)552         private void setAlertsEnabled(boolean alertsEnabled) {
553             if (mSevereCheckBox != null) {
554                 mSevereCheckBox.setEnabled(alertsEnabled);
555                 mSevereCheckBox.setChecked(alertsEnabled);
556             }
557             if (mExtremeCheckBox != null) {
558                 mExtremeCheckBox.setEnabled(alertsEnabled);
559                 mExtremeCheckBox.setChecked(alertsEnabled);
560             }
561             if (mAmberCheckBox != null) {
562                 mAmberCheckBox.setEnabled(alertsEnabled);
563                 mAmberCheckBox.setChecked(alertsEnabled);
564             }
565             if (mAreaUpdateInfoCheckBox != null) {
566                 mAreaUpdateInfoCheckBox.setEnabled(alertsEnabled);
567                 mAreaUpdateInfoCheckBox.setChecked(alertsEnabled);
568             }
569             if (mAlertPreferencesCategory != null) {
570                 mAlertPreferencesCategory.setEnabled(alertsEnabled);
571             }
572             if (mEmergencyAlertsCheckBox != null) {
573                 mEmergencyAlertsCheckBox.setEnabled(alertsEnabled);
574                 mEmergencyAlertsCheckBox.setChecked(alertsEnabled);
575             }
576             if (mPublicSafetyMessagesChannelCheckBox != null) {
577                 mPublicSafetyMessagesChannelCheckBox.setEnabled(alertsEnabled);
578                 mPublicSafetyMessagesChannelCheckBox.setChecked(alertsEnabled);
579             }
580             if (mStateLocalTestCheckBox != null) {
581                 mStateLocalTestCheckBox.setEnabled(alertsEnabled);
582                 mStateLocalTestCheckBox.setChecked(alertsEnabled);
583             }
584             if (mTestCheckBox != null) {
585                 mTestCheckBox.setEnabled(alertsEnabled);
586                 mTestCheckBox.setChecked(alertsEnabled);
587             }
588         }
589 
590         @Override
onResume()591         public void onResume() {
592             super.onResume();
593             updatePreferenceVisibility();
594         }
595 
596         @Override
onDestroy()597         public void onDestroy() {
598             super.onDestroy();
599             LocalBroadcastManager.getInstance(getContext())
600                     .unregisterReceiver(mTestingModeChangedReeiver);
601         }
602     }
603 
isTestAlertsToggleVisible(Context context)604     public static boolean isTestAlertsToggleVisible(Context context) {
605         CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager(context,
606                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
607         Resources res = CellBroadcastSettings.getResources(context,
608                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
609         boolean isTestAlertsAvailable = !channelManager.getCellBroadcastChannelRanges(
610                 R.array.required_monthly_test_range_strings).isEmpty()
611                 || !channelManager.getCellBroadcastChannelRanges(
612                 R.array.exercise_alert_range_strings).isEmpty()
613                 || !channelManager.getCellBroadcastChannelRanges(
614                 R.array.operator_defined_alert_range_strings).isEmpty()
615                 || !channelManager.getCellBroadcastChannelRanges(
616                 R.array.etws_test_alerts_range_strings).isEmpty();
617 
618         return (res.getBoolean(R.bool.show_test_settings)
619                 || CellBroadcastReceiver.isTestingMode(context))
620                 && isTestAlertsAvailable;
621     }
622 
isFeatureEnabled(Context context, String feature, boolean defaultValue)623     public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) {
624         CarrierConfigManager configManager =
625                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
626 
627         if (configManager != null) {
628             PersistableBundle carrierConfig = configManager.getConfig();
629             if (carrierConfig != null) {
630                 return carrierConfig.getBoolean(feature, defaultValue);
631             }
632         }
633 
634         return defaultValue;
635     }
636 
637     /**
638      * Override used by tests so that we don't call
639      * SubscriptionManager.getResourcesForSubId, which is a static unmockable
640      * method.
641      */
642     @VisibleForTesting
setUseResourcesForSubId(boolean useResourcesForSubId)643     public static void setUseResourcesForSubId(boolean useResourcesForSubId) {
644         sUseResourcesForSubId = useResourcesForSubId;
645     }
646 
647     /**
648      * Get the device resource based on SIM
649      *
650      * @param context Context
651      * @param subId Subscription index
652      *
653      * @return The resource
654      */
getResources(@onNull Context context, int subId)655     public static @NonNull Resources getResources(@NonNull Context context, int subId) {
656         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID
657                 || !SubscriptionManager.isValidSubscriptionId(subId) || !sUseResourcesForSubId) {
658             return context.getResources();
659         }
660 
661         if (sResourcesCache.containsKey(subId)) {
662             return sResourcesCache.get(subId);
663         }
664 
665         Resources res = SubscriptionManager.getResourcesForSubId(context, subId);
666         sResourcesCache.put(subId, res);
667 
668         return res;
669     }
670 }
671