Home | History | Annotate | Download | only in cellbroadcastreceiver
      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.app.ActionBar;
     20 import android.app.Activity;
     21 import android.app.Fragment;
     22 import android.app.backup.BackupManager;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.pm.PackageManager;
     26 import android.content.res.Resources;
     27 import android.os.Bundle;
     28 import android.os.PersistableBundle;
     29 import android.os.UserManager;
     30 import android.provider.Settings;
     31 import android.support.v14.preference.PreferenceFragment;
     32 import android.support.v7.preference.ListPreference;
     33 import android.support.v7.preference.Preference;
     34 import android.support.v7.preference.PreferenceCategory;
     35 import android.support.v7.preference.PreferenceScreen;
     36 import android.support.v7.preference.TwoStatePreference;
     37 import android.telephony.CarrierConfigManager;
     38 import android.telephony.SubscriptionManager;
     39 import android.util.Log;
     40 import android.view.MenuItem;
     41 
     42 
     43 /**
     44  * Settings activity for the cell broadcast receiver.
     45  */
     46 public class CellBroadcastSettings extends Activity {
     47 
     48     private static final String TAG = "CellBroadcastSettings";
     49 
     50     private static final boolean DBG = false;
     51 
     52     // Preference key for a master toggle to enable/disable all alerts message (default enabled).
     53     public static final String KEY_ENABLE_ALERTS_MASTER_TOGGLE = "enable_alerts_master_toggle";
     54 
     55     // Preference key for whether to enable public safety messages (default enabled).
     56     public static final String KEY_ENABLE_PUBLIC_SAFETY_MESSAGES = "enable_public_safety_messages";
     57 
     58     // Preference key for whether to enable emergency alerts (default enabled).
     59     public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts";
     60 
     61     // Enable vibration on alert (unless master volume is silent).
     62     public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate";
     63 
     64     // Speak contents of alert after playing the alert sound.
     65     public static final String KEY_ENABLE_ALERT_SPEECH = "enable_alert_speech";
     66 
     67     // Always play at full volume when playing the alert sound.
     68     public static final String KEY_USE_FULL_VOLUME = "use_full_volume";
     69 
     70     // Preference category for emergency alert and CMAS settings.
     71     public static final String KEY_CATEGORY_EMERGENCY_ALERTS = "category_emergency_alerts";
     72 
     73     // Preference category for alert preferences.
     74     public static final String KEY_CATEGORY_ALERT_PREFERENCES = "category_alert_preferences";
     75 
     76     // Whether to display CMAS extreme threat notifications (default is enabled).
     77     public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS =
     78             "enable_cmas_extreme_threat_alerts";
     79 
     80     // Whether to display CMAS severe threat notifications (default is enabled).
     81     public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS =
     82             "enable_cmas_severe_threat_alerts";
     83 
     84     // Whether to display CMAS amber alert messages (default is enabled).
     85     public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts";
     86 
     87     // Preference category for development settings (enabled by settings developer options toggle).
     88     public static final String KEY_CATEGORY_DEV_SETTINGS = "category_dev_settings";
     89 
     90     // Whether to display monthly test messages (default is disabled).
     91     public static final String KEY_ENABLE_TEST_ALERTS = "enable_test_alerts";
     92 
     93     // Preference key for whether to enable area update information notifications
     94     // Enabled by default for phones sold in Brazil and India, otherwise this setting may be hidden.
     95     public static final String KEY_ENABLE_AREA_UPDATE_INFO_ALERTS =
     96             "enable_area_update_info_alerts";
     97 
     98     // Preference key for initial opt-in/opt-out dialog.
     99     public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
    100 
    101     // Alert reminder interval ("once" = single 2 minute reminder).
    102     public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
    103 
    104     // Preference key for emergency alerts history
    105     public static final String KEY_EMERGENCY_ALERT_HISTORY = "emergency_alert_history";
    106 
    107     // For watch layout
    108     private static final String KEY_WATCH_ALERT_REMINDER = "watch_alert_reminder";
    109 
    110     @Override
    111     public void onCreate(Bundle savedInstanceState) {
    112         super.onCreate(savedInstanceState);
    113 
    114         ActionBar actionBar = getActionBar();
    115         if (actionBar != null) {
    116             // android.R.id.home will be triggered in onOptionsItemSelected()
    117             actionBar.setDisplayHomeAsUpEnabled(true);
    118         }
    119 
    120         UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
    121         if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) {
    122             setContentView(R.layout.cell_broadcast_disallowed_preference_screen);
    123             return;
    124         }
    125 
    126         // We only add new CellBroadcastSettingsFragment if no fragment is restored.
    127         Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content);
    128         if (fragment == null) {
    129             getFragmentManager().beginTransaction().add(android.R.id.content,
    130                     new CellBroadcastSettingsFragment()).commit();
    131         }
    132     }
    133 
    134     @Override
    135     public boolean onOptionsItemSelected(MenuItem item) {
    136         switch (item.getItemId()) {
    137             // Respond to the action bar's Up/Home button
    138             case android.R.id.home:
    139                 finish();
    140                 return true;
    141         }
    142         return super.onOptionsItemSelected(item);
    143     }
    144 
    145     /**
    146      * New fragment-style implementation of preferences.
    147      */
    148     public static class CellBroadcastSettingsFragment extends PreferenceFragment {
    149 
    150         private TwoStatePreference mExtremeCheckBox;
    151         private TwoStatePreference mSevereCheckBox;
    152         private TwoStatePreference mAmberCheckBox;
    153         private TwoStatePreference mMasterToggle;
    154         private TwoStatePreference mPublicSafetyMessagesChannelCheckBox;
    155         private TwoStatePreference mEmergencyAlertsCheckBox;
    156         private ListPreference mReminderInterval;
    157         private TwoStatePreference mSpeechCheckBox;
    158         private TwoStatePreference mFullVolumeCheckBox;
    159         private TwoStatePreference mAreaUpdateInfoCheckBox;
    160         private TwoStatePreference mTestCheckBox;
    161         private Preference mAlertHistory;
    162         private PreferenceCategory mAlertCategory;
    163         private PreferenceCategory mAlertPreferencesCategory;
    164         private PreferenceCategory mDevSettingCategory;
    165         private boolean mDisableSevereWhenExtremeDisabled = true;
    166 
    167         // WATCH
    168         private TwoStatePreference mAlertReminder;
    169 
    170         @Override
    171         public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
    172 
    173             // Load the preferences from an XML resource
    174             PackageManager pm = getActivity().getPackageManager();
    175             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    176                 addPreferencesFromResource(R.xml.watch_preferences);
    177             } else {
    178                 addPreferencesFromResource(R.xml.preferences);
    179             }
    180 
    181             PreferenceScreen preferenceScreen = getPreferenceScreen();
    182 
    183             mExtremeCheckBox = (TwoStatePreference)
    184                     findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS);
    185             mSevereCheckBox = (TwoStatePreference)
    186                     findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS);
    187             mAmberCheckBox = (TwoStatePreference)
    188                     findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS);
    189             mMasterToggle = (TwoStatePreference)
    190                     findPreference(KEY_ENABLE_ALERTS_MASTER_TOGGLE);
    191             mPublicSafetyMessagesChannelCheckBox = (TwoStatePreference)
    192                     findPreference(KEY_ENABLE_PUBLIC_SAFETY_MESSAGES);
    193             mEmergencyAlertsCheckBox = (TwoStatePreference)
    194                     findPreference(KEY_ENABLE_EMERGENCY_ALERTS);
    195             mReminderInterval = (ListPreference)
    196                     findPreference(KEY_ALERT_REMINDER_INTERVAL);
    197             mSpeechCheckBox = (TwoStatePreference)
    198                     findPreference(KEY_ENABLE_ALERT_SPEECH);
    199             mFullVolumeCheckBox = (TwoStatePreference)
    200                     findPreference(KEY_USE_FULL_VOLUME);
    201             mAreaUpdateInfoCheckBox = (TwoStatePreference)
    202                     findPreference(KEY_ENABLE_AREA_UPDATE_INFO_ALERTS);
    203             mTestCheckBox = (TwoStatePreference)
    204                     findPreference(KEY_ENABLE_TEST_ALERTS);
    205             mAlertHistory = findPreference(KEY_EMERGENCY_ALERT_HISTORY);
    206             mDevSettingCategory = (PreferenceCategory)
    207                     findPreference(KEY_CATEGORY_DEV_SETTINGS);
    208 
    209             if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    210                 mAlertReminder = (TwoStatePreference)
    211                         findPreference(KEY_WATCH_ALERT_REMINDER);
    212                 if (Integer.valueOf(mReminderInterval.getValue()) == 0) {
    213                     mAlertReminder.setChecked(false);
    214                 } else {
    215                     mAlertReminder.setChecked(true);
    216                 }
    217                 mAlertReminder.setOnPreferenceChangeListener((p, newVal) -> {
    218                     try {
    219                         mReminderInterval.setValueIndex((Boolean) newVal ? 1 : 3);
    220                     } catch (IndexOutOfBoundsException e) {
    221                         mReminderInterval.setValue(String.valueOf(0));
    222                         Log.w(TAG, "Setting default value");
    223                     }
    224                     return true;
    225                 });
    226                 PreferenceScreen watchScreen = (PreferenceScreen)
    227                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
    228                 watchScreen.removePreference(mReminderInterval);
    229             } else {
    230                 mAlertPreferencesCategory = (PreferenceCategory)
    231                         findPreference(KEY_CATEGORY_ALERT_PREFERENCES);
    232                 mAlertCategory = (PreferenceCategory)
    233                         findPreference(KEY_CATEGORY_EMERGENCY_ALERTS);
    234             }
    235 
    236 
    237             mDisableSevereWhenExtremeDisabled = isFeatureEnabled(getContext(),
    238                     CarrierConfigManager.KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
    239 
    240             // Handler for settings that require us to reconfigure enabled channels in radio
    241             Preference.OnPreferenceChangeListener startConfigServiceListener =
    242                     new Preference.OnPreferenceChangeListener() {
    243                         @Override
    244                         public boolean onPreferenceChange(Preference pref, Object newValue) {
    245                             CellBroadcastReceiver.startConfigService(pref.getContext());
    246 
    247                             if (mDisableSevereWhenExtremeDisabled) {
    248                                 if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) {
    249                                     boolean isExtremeAlertChecked = (Boolean) newValue;
    250                                     if (mSevereCheckBox != null) {
    251                                         mSevereCheckBox.setEnabled(isExtremeAlertChecked);
    252                                         mSevereCheckBox.setChecked(false);
    253                                     }
    254                                 }
    255                             }
    256 
    257                             if (pref.getKey().equals(KEY_ENABLE_ALERTS_MASTER_TOGGLE)) {
    258                                 boolean isEnableAlerts = (Boolean) newValue;
    259                                 setAlertsEnabled(isEnableAlerts);
    260                             }
    261 
    262                             // Notify backup manager a backup pass is needed.
    263                             new BackupManager(getContext()).dataChanged();
    264                             return true;
    265                         }
    266                     };
    267 
    268             // Show extra settings when developer options is enabled in settings.
    269             boolean enableDevSettings = Settings.Global.getInt(getContext().getContentResolver(),
    270                     Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
    271 
    272             Resources res = getResources();
    273 
    274             initReminderIntervalList();
    275 
    276             boolean emergencyAlertOnOffOptionEnabled = isFeatureEnabled(getContext(),
    277                     CarrierConfigManager.KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
    278 
    279             if (enableDevSettings || emergencyAlertOnOffOptionEnabled) {
    280                 // enable/disable all alerts except CMAS presidential alerts.
    281                 if (mMasterToggle != null) {
    282                     mMasterToggle.setOnPreferenceChangeListener(startConfigServiceListener);
    283                     // If allow alerts are disabled, we turn all sub-alerts off. If it's enabled, we
    284                     // leave them as they are.
    285                     if (!mMasterToggle.isChecked()) {
    286                         setAlertsEnabled(false);
    287                     }
    288                 }
    289             } else {
    290                 if (mMasterToggle != null) preferenceScreen.removePreference(mMasterToggle);
    291             }
    292 
    293             boolean hideTestAlertMenu = CellBroadcastSettings.isFeatureEnabled(getContext(),
    294                     CarrierConfigManager.KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
    295 
    296             // Check if we want to hide the test alert toggle.
    297             if (hideTestAlertMenu || !enableDevSettings || !isTestAlertsAvailable()) {
    298                 if (mTestCheckBox != null) {
    299                     mAlertCategory.removePreference(mTestCheckBox);
    300                 }
    301             }
    302 
    303             if (!enableDevSettings && !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    304                 if (mDevSettingCategory != null) {
    305                     preferenceScreen.removePreference(mDevSettingCategory);
    306                 }
    307             }
    308 
    309             // Remove preferences
    310             if (!res.getBoolean(R.bool.show_cmas_settings)) {
    311                 // Remove CMAS preference items in emergency alert category.
    312                 if (mAlertCategory != null) {
    313                     if (mExtremeCheckBox != null) mAlertCategory.removePreference(mExtremeCheckBox);
    314                     if (mSevereCheckBox != null) mAlertCategory.removePreference(mSevereCheckBox);
    315                     if (mAmberCheckBox != null) mAlertCategory.removePreference(mAmberCheckBox);
    316                 }
    317             }
    318 
    319             if (!Resources.getSystem().getBoolean(
    320                     com.android.internal.R.bool.config_showAreaUpdateInfoSettings)) {
    321                 if (mAlertCategory != null) {
    322                     if (mAreaUpdateInfoCheckBox != null) {
    323                         mAlertCategory.removePreference(mAreaUpdateInfoCheckBox);
    324                     }
    325                 }
    326             }
    327 
    328             // Remove preferences based on range configurations
    329             if (CellBroadcastChannelManager.getCellBroadcastChannelRanges(
    330                     this.getContext(),
    331                     R.array.public_safety_messages_channels_range_strings).isEmpty()) {
    332                 // Remove public safety messages
    333                 if (mAlertCategory != null) {
    334                     if (mPublicSafetyMessagesChannelCheckBox != null) {
    335                         mAlertCategory.removePreference(mPublicSafetyMessagesChannelCheckBox);
    336                     }
    337                 }
    338             }
    339 
    340             if (CellBroadcastChannelManager.getCellBroadcastChannelRanges(
    341                     this.getContext(), R.array.emergency_alerts_channels_range_strings).isEmpty()) {
    342                 // Remove emergency alert messages
    343                 if (mAlertCategory != null) {
    344                     if (mEmergencyAlertsCheckBox != null) {
    345                         mAlertCategory.removePreference(mEmergencyAlertsCheckBox);
    346                     }
    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 
    378             if (mAlertHistory != null) {
    379                 mAlertHistory.setOnPreferenceClickListener(
    380                         new Preference.OnPreferenceClickListener() {
    381                             @Override
    382                             public boolean onPreferenceClick(final Preference preference) {
    383                                 final Intent intent = new Intent(getContext(),
    384                                         CellBroadcastListActivity.class);
    385                                 startActivity(intent);
    386                                 return true;
    387                             }
    388                         });
    389             }
    390         }
    391 
    392         private boolean isTestAlertsAvailable() {
    393             return !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
    394                     this.getContext(), R.array.required_monthly_test_range_strings).isEmpty()
    395                     || !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
    396                             this.getContext(), R.array.exercise_alert_range_strings).isEmpty()
    397                     || !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
    398                             this.getContext(), R.array.operator_defined_alert_range_strings)
    399                     .isEmpty()
    400                     || !CellBroadcastChannelManager.getCellBroadcastChannelRanges(
    401                             this.getContext(), R.array.etws_test_alerts_range_strings).isEmpty();
    402         }
    403 
    404         private void initReminderIntervalList() {
    405 
    406             String[] activeValues =
    407                     getResources().getStringArray(R.array.alert_reminder_interval_active_values);
    408             String[] allEntries =
    409                     getResources().getStringArray(R.array.alert_reminder_interval_entries);
    410             String[] newEntries = new String[activeValues.length];
    411 
    412             // Only add active interval to the list
    413             for (int i = 0; i < activeValues.length; i++) {
    414                 int index = mReminderInterval.findIndexOfValue(activeValues[i]);
    415                 if (index != -1) {
    416                     newEntries[i] = allEntries[index];
    417                     if (DBG) Log.d(TAG, "Added " + allEntries[index]);
    418                 } else {
    419                     Log.e(TAG, "Can't find " + activeValues[i]);
    420                 }
    421             }
    422 
    423             mReminderInterval.setEntries(newEntries);
    424             mReminderInterval.setEntryValues(activeValues);
    425             mReminderInterval.setSummary(mReminderInterval.getEntry());
    426             mReminderInterval.setOnPreferenceChangeListener(
    427                     new Preference.OnPreferenceChangeListener() {
    428                         @Override
    429                         public boolean onPreferenceChange(Preference pref, Object newValue) {
    430                             final ListPreference listPref = (ListPreference) pref;
    431                             final int idx = listPref.findIndexOfValue((String) newValue);
    432                             listPref.setSummary(listPref.getEntries()[idx]);
    433                             return true;
    434                         }
    435                     });
    436         }
    437 
    438 
    439         private void setAlertsEnabled(boolean alertsEnabled) {
    440             if (mSevereCheckBox != null) {
    441                 mSevereCheckBox.setEnabled(alertsEnabled);
    442                 mSevereCheckBox.setChecked(alertsEnabled);
    443             }
    444             if (mExtremeCheckBox != null) {
    445                 mExtremeCheckBox.setEnabled(alertsEnabled);
    446                 mExtremeCheckBox.setChecked(alertsEnabled);
    447             }
    448             if (mAmberCheckBox != null) {
    449                 mAmberCheckBox.setEnabled(alertsEnabled);
    450                 mAmberCheckBox.setChecked(alertsEnabled);
    451             }
    452             if (mAreaUpdateInfoCheckBox != null) {
    453                 mAreaUpdateInfoCheckBox.setEnabled(alertsEnabled);
    454                 mAreaUpdateInfoCheckBox.setChecked(alertsEnabled);
    455             }
    456             if (mAlertPreferencesCategory != null) {
    457                 mAlertPreferencesCategory.setEnabled(alertsEnabled);
    458             }
    459             if (mDevSettingCategory != null) {
    460                 mDevSettingCategory.setEnabled(alertsEnabled);
    461             }
    462             if (mEmergencyAlertsCheckBox != null) {
    463                 mEmergencyAlertsCheckBox.setEnabled(alertsEnabled);
    464                 mEmergencyAlertsCheckBox.setChecked(alertsEnabled);
    465             }
    466             if (mPublicSafetyMessagesChannelCheckBox != null) {
    467                 mPublicSafetyMessagesChannelCheckBox.setEnabled(alertsEnabled);
    468                 mPublicSafetyMessagesChannelCheckBox.setChecked(alertsEnabled);
    469             }
    470         }
    471     }
    472 
    473     public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) {
    474         int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
    475         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
    476             subId = SubscriptionManager.getDefaultSubscriptionId();
    477             if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
    478                 return defaultValue;
    479             }
    480         }
    481 
    482         CarrierConfigManager configManager =
    483                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
    484 
    485         if (configManager != null) {
    486             PersistableBundle carrierConfig = configManager.getConfigForSubId(subId);
    487 
    488             if (carrierConfig != null) {
    489                 return carrierConfig.getBoolean(feature, defaultValue);
    490             }
    491         }
    492 
    493         return defaultValue;
    494     }
    495 }
    496