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
17package com.android.cellbroadcastreceiver;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.os.Bundle;
22import android.os.PersistableBundle;
23import android.os.UserManager;
24import android.preference.CheckBoxPreference;
25import android.preference.ListPreference;
26import android.preference.Preference;
27import android.preference.PreferenceActivity;
28import android.preference.PreferenceCategory;
29import android.preference.PreferenceFragment;
30import android.preference.PreferenceScreen;
31import android.provider.Settings;
32import android.telephony.CarrierConfigManager;
33import android.telephony.SubscriptionManager;
34import android.telephony.TelephonyManager;
35import android.util.Log;
36
37/**
38 * Settings activity for the cell broadcast receiver.
39 */
40public class CellBroadcastSettings extends PreferenceActivity {
41
42    private static final String TAG = "CellBroadcastSettings";
43
44    private static final boolean DBG = false;
45
46    // Preference key for whether to enable emergency notifications (default enabled).
47    public static final String KEY_ENABLE_EMERGENCY_ALERTS = "enable_emergency_alerts";
48
49    // Enable vibration on alert (unless master volume is silent).
50    public static final String KEY_ENABLE_ALERT_VIBRATE = "enable_alert_vibrate";
51
52    // Speak contents of alert after playing the alert sound.
53    public static final String KEY_ENABLE_ALERT_SPEECH = "enable_alert_speech";
54
55    // Preference category for emergency alert and CMAS settings.
56    public static final String KEY_CATEGORY_ALERT_SETTINGS = "category_alert_settings";
57
58    // Preference category for ETWS related settings.
59    public static final String KEY_CATEGORY_ETWS_SETTINGS = "category_etws_settings";
60
61    // Whether to display CMAS extreme threat notifications (default is enabled).
62    public static final String KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS =
63            "enable_cmas_extreme_threat_alerts";
64
65    // Whether to display CMAS severe threat notifications (default is enabled).
66    public static final String KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS =
67            "enable_cmas_severe_threat_alerts";
68
69    // Whether to display CMAS amber alert messages (default is enabled).
70    public static final String KEY_ENABLE_CMAS_AMBER_ALERTS = "enable_cmas_amber_alerts";
71
72    // Preference category for development settings (enabled by settings developer options toggle).
73    public static final String KEY_CATEGORY_DEV_SETTINGS = "category_dev_settings";
74
75    // Whether to display ETWS test messages (default is disabled).
76    public static final String KEY_ENABLE_ETWS_TEST_ALERTS = "enable_etws_test_alerts";
77
78    // Whether to display CMAS monthly test messages (default is disabled).
79    public static final String KEY_ENABLE_CMAS_TEST_ALERTS = "enable_cmas_test_alerts";
80
81    // Preference category for Brazil specific settings.
82    public static final String KEY_CATEGORY_BRAZIL_SETTINGS = "category_brazil_settings";
83
84    // Preference key for whether to enable channel 50 notifications
85    // Enabled by default for phones sold in Brazil, otherwise this setting may be hidden.
86    public static final String KEY_ENABLE_CHANNEL_50_ALERTS = "enable_channel_50_alerts";
87
88    // Preference key for initial opt-in/opt-out dialog.
89    public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
90
91    // Alert reminder interval ("once" = single 2 minute reminder).
92    public static final String KEY_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
93
94    // Brazil country code
95    private static final String COUNTRY_BRAZIL = "br";
96
97    @Override
98    public void onCreate(Bundle savedInstanceState) {
99        super.onCreate(savedInstanceState);
100
101        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
102        if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) {
103            setContentView(R.layout.cell_broadcast_disallowed_preference_screen);
104            return;
105        }
106
107        // Display the fragment as the main content.
108        getFragmentManager().beginTransaction().replace(android.R.id.content,
109                new CellBroadcastSettingsFragment()).commit();
110    }
111
112    /**
113     * New fragment-style implementation of preferences.
114     */
115    public static class CellBroadcastSettingsFragment extends PreferenceFragment {
116
117        private CheckBoxPreference mExtremeCheckBox;
118        private CheckBoxPreference mSevereCheckBox;
119        private CheckBoxPreference mAmberCheckBox;
120        private CheckBoxPreference mEmergencyCheckBox;
121        private ListPreference mReminderInterval;
122        private CheckBoxPreference mSpeechCheckBox;
123        private CheckBoxPreference mEtwsTestCheckBox;
124        private CheckBoxPreference mChannel50CheckBox;
125        private CheckBoxPreference mCmasTestCheckBox;
126        private PreferenceCategory mAlertCategory;
127        private PreferenceCategory mETWSSettingCategory;
128        private boolean mDisableSevereWhenExtremeDisabled = true;
129
130        @Override
131        public void onCreate(Bundle savedInstanceState) {
132            super.onCreate(savedInstanceState);
133
134            // Load the preferences from an XML resource
135            addPreferencesFromResource(R.xml.preferences);
136
137            PreferenceScreen preferenceScreen = getPreferenceScreen();
138
139            mExtremeCheckBox = (CheckBoxPreference)
140                    findPreference(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS);
141            mSevereCheckBox = (CheckBoxPreference)
142                    findPreference(KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS);
143            mAmberCheckBox = (CheckBoxPreference)
144                    findPreference(KEY_ENABLE_CMAS_AMBER_ALERTS);
145            mEmergencyCheckBox = (CheckBoxPreference)
146                    findPreference(KEY_ENABLE_EMERGENCY_ALERTS);
147            mReminderInterval = (ListPreference)
148                    findPreference(KEY_ALERT_REMINDER_INTERVAL);
149            mSpeechCheckBox = (CheckBoxPreference)
150                    findPreference(KEY_ENABLE_ALERT_SPEECH);
151            mEtwsTestCheckBox = (CheckBoxPreference)
152                    findPreference(KEY_ENABLE_ETWS_TEST_ALERTS);
153            mChannel50CheckBox = (CheckBoxPreference)
154                    findPreference(KEY_ENABLE_CHANNEL_50_ALERTS);
155            mCmasTestCheckBox = (CheckBoxPreference)
156                    findPreference(KEY_ENABLE_CMAS_TEST_ALERTS);
157            mAlertCategory = (PreferenceCategory)
158                    findPreference(KEY_CATEGORY_ALERT_SETTINGS);
159            mETWSSettingCategory = (PreferenceCategory)
160                    findPreference(KEY_CATEGORY_ETWS_SETTINGS);
161
162            mDisableSevereWhenExtremeDisabled = isFeatureEnabled(getContext(),
163                    CarrierConfigManager.KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
164
165            // Handler for settings that require us to reconfigure enabled channels in radio
166            Preference.OnPreferenceChangeListener startConfigServiceListener =
167                    new Preference.OnPreferenceChangeListener() {
168                        @Override
169                        public boolean onPreferenceChange(Preference pref, Object newValue) {
170                            CellBroadcastReceiver.startConfigService(pref.getContext());
171
172                            if (mDisableSevereWhenExtremeDisabled) {
173                                if (pref.getKey().equals(KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS)) {
174                                    boolean isExtremeAlertChecked = (Boolean)newValue;
175                                    if (mSevereCheckBox != null) {
176                                        mSevereCheckBox.setEnabled(isExtremeAlertChecked);
177                                        mSevereCheckBox.setChecked(false);
178                                    }
179                                }
180                            }
181
182                            return true;
183                        }
184                    };
185
186            // Show extra settings when developer options is enabled in settings.
187            boolean enableDevSettings = Settings.Global.getInt(getContext().getContentResolver(),
188                    Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
189
190            Resources res = getResources();
191            boolean showEtwsSettings = res.getBoolean(R.bool.show_etws_settings);
192
193            initReminderIntervalList();
194
195            boolean forceDisableEtwsCmasTest = CellBroadcastSettings.isFeatureEnabled(getContext(),
196                    CarrierConfigManager.KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
197
198            boolean emergencyAlertOnOffOptionEnabled = isFeatureEnabled(getContext(),
199                    CarrierConfigManager.KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
200
201            if (enableDevSettings || showEtwsSettings || emergencyAlertOnOffOptionEnabled) {
202                // enable/disable all alerts except CMAS presidential alerts.
203                if (mEmergencyCheckBox != null) {
204                    mEmergencyCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
205                }
206            } else {
207                mAlertCategory.removePreference(mEmergencyCheckBox);
208            }
209
210            // Show alert settings and ETWS categories for ETWS builds and developer mode.
211            if (enableDevSettings || showEtwsSettings) {
212
213                if (forceDisableEtwsCmasTest) {
214                    // Remove ETWS test preference.
215                    preferenceScreen.removePreference(mETWSSettingCategory);
216
217                    PreferenceCategory devSettingCategory =
218                            (PreferenceCategory) findPreference(KEY_CATEGORY_DEV_SETTINGS);
219
220                    // Remove CMAS test preference.
221                    if (devSettingCategory != null) {
222                        devSettingCategory.removePreference(mCmasTestCheckBox);
223                    }
224                }
225            } else {
226                mAlertCategory.removePreference(mSpeechCheckBox);
227                // Remove ETWS test preference category.
228                preferenceScreen.removePreference(mETWSSettingCategory);
229            }
230
231            if (!res.getBoolean(R.bool.show_cmas_settings)) {
232                // Remove CMAS preference items in emergency alert category.
233                mAlertCategory.removePreference(mExtremeCheckBox);
234                mAlertCategory.removePreference(mSevereCheckBox);
235                mAlertCategory.removePreference(mAmberCheckBox);
236            }
237
238            TelephonyManager tm = (TelephonyManager) getContext().getSystemService(
239                    Context.TELEPHONY_SERVICE);
240
241            // We display channel 50 enable/disable menu if one of the followings is true
242            // 1. The setting through resource overlay is set to true.
243            // 2. At least one SIM inserted is Brazilian SIM.
244
245            boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings);
246
247            if (!enableChannel50Support) {
248                SubscriptionManager sm = SubscriptionManager.from(getContext());
249                for (int subId : sm.getActiveSubscriptionIdList()) {
250                    if (COUNTRY_BRAZIL.equals(tm.getSimCountryIso(subId))) {
251                        enableChannel50Support = true;
252                        break;
253                    }
254                }
255            }
256
257            if (!enableChannel50Support) {
258                preferenceScreen.removePreference(findPreference(KEY_CATEGORY_BRAZIL_SETTINGS));
259            }
260            if (!enableDevSettings) {
261                preferenceScreen.removePreference(findPreference(KEY_CATEGORY_DEV_SETTINGS));
262            }
263
264            if (mChannel50CheckBox != null) {
265                mChannel50CheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
266            }
267            if (mEtwsTestCheckBox != null) {
268                mEtwsTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
269            }
270            if (mExtremeCheckBox != null) {
271                mExtremeCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
272            }
273
274            if (mSevereCheckBox != null) {
275                mSevereCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
276                if (mDisableSevereWhenExtremeDisabled) {
277                    if (mExtremeCheckBox != null) {
278                        mSevereCheckBox.setEnabled(mExtremeCheckBox.isChecked());
279                    }
280                }
281            }
282            if (mAmberCheckBox != null) {
283                mAmberCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
284            }
285            if (mCmasTestCheckBox != null) {
286                mCmasTestCheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
287            }
288        }
289
290        private void initReminderIntervalList() {
291
292            String[] activeValues =
293                    getResources().getStringArray(R.array.alert_reminder_interval_active_values);
294            String[] allEntries =
295                    getResources().getStringArray(R.array.alert_reminder_interval_entries);
296            String[] newEntries = new String[activeValues.length];
297
298            // Only add active interval to the list
299            for (int i = 0; i < activeValues.length; i++) {
300                int index = mReminderInterval.findIndexOfValue(activeValues[i]);
301                if (index != -1) {
302                    newEntries[i] = allEntries[index];
303                    if (DBG) Log.d(TAG, "Added " + allEntries[index]);
304                } else {
305                    Log.e(TAG, "Can't find " + activeValues[i]);
306                }
307            }
308
309            mReminderInterval.setEntries(newEntries);
310            mReminderInterval.setEntryValues(activeValues);
311            mReminderInterval.setSummary(mReminderInterval.getEntry());
312            mReminderInterval.setOnPreferenceChangeListener(
313                    new Preference.OnPreferenceChangeListener() {
314                        @Override
315                        public boolean onPreferenceChange(Preference pref, Object newValue) {
316                            final ListPreference listPref = (ListPreference) pref;
317                            final int idx = listPref.findIndexOfValue((String) newValue);
318                            listPref.setSummary(listPref.getEntries()[idx]);
319                            return true;
320                        }
321                    });
322        }
323    }
324
325    public static boolean isFeatureEnabled(Context context, String feature, boolean defaultValue) {
326        int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
327        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
328            subId = SubscriptionManager.getDefaultSubscriptionId();
329            if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
330                return defaultValue;
331            }
332        }
333
334        CarrierConfigManager configManager =
335                (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
336
337        if (configManager != null) {
338            PersistableBundle carrierConfig = configManager.getConfigForSubId(subId);
339
340            if (carrierConfig != null) {
341                return carrierConfig.getBoolean(feature, defaultValue);
342            }
343        }
344
345        return defaultValue;
346    }
347}
348