1/*
2 * Copyright (C) 2007-2008 Esmertec AG.
3 * Copyright (C) 2007-2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.ui;
19
20import android.app.ActionBar;
21import android.app.AlertDialog;
22import android.app.Dialog;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.SharedPreferences;
27import android.media.Ringtone;
28import android.media.RingtoneManager;
29import android.net.Uri;
30import android.os.Bundle;
31import android.preference.CheckBoxPreference;
32import android.preference.Preference;
33import android.preference.Preference.OnPreferenceChangeListener;
34import android.preference.PreferenceActivity;
35import android.preference.PreferenceCategory;
36import android.preference.PreferenceManager;
37import android.preference.PreferenceScreen;
38import android.preference.RingtonePreference;
39import android.provider.SearchRecentSuggestions;
40import android.text.TextUtils;
41import android.view.Menu;
42import android.view.MenuItem;
43
44import com.android.mms.MmsApp;
45import com.android.mms.MmsConfig;
46import com.android.mms.R;
47import com.android.mms.transaction.TransactionService;
48import com.android.mms.util.Recycler;
49
50/**
51 * With this activity, users can set preferences for MMS and SMS and
52 * can access and manipulate SMS messages stored on the SIM.
53 */
54public class MessagingPreferenceActivity extends PreferenceActivity
55            implements OnPreferenceChangeListener {
56    // Symbolic names for the keys used for preference lookup
57    public static final String MMS_DELIVERY_REPORT_MODE = "pref_key_mms_delivery_reports";
58    public static final String EXPIRY_TIME              = "pref_key_mms_expiry";
59    public static final String PRIORITY                 = "pref_key_mms_priority";
60    public static final String READ_REPORT_MODE         = "pref_key_mms_read_reports";
61    public static final String SMS_DELIVERY_REPORT_MODE = "pref_key_sms_delivery_reports";
62    public static final String NOTIFICATION_ENABLED     = "pref_key_enable_notifications";
63    public static final String NOTIFICATION_VIBRATE     = "pref_key_vibrate";
64    public static final String NOTIFICATION_VIBRATE_WHEN= "pref_key_vibrateWhen";
65    public static final String NOTIFICATION_RINGTONE    = "pref_key_ringtone";
66    public static final String AUTO_RETRIEVAL           = "pref_key_mms_auto_retrieval";
67    public static final String RETRIEVAL_DURING_ROAMING = "pref_key_mms_retrieval_during_roaming";
68    public static final String AUTO_DELETE              = "pref_key_auto_delete";
69    public static final String GROUP_MMS_MODE           = "pref_key_mms_group_mms";
70
71    // Menu entries
72    private static final int MENU_RESTORE_DEFAULTS    = 1;
73
74    // Preferences for enabling and disabling SMS
75    private Preference mSmsDisabledPref;
76    private Preference mSmsEnabledPref;
77
78    private PreferenceCategory mStoragePrefCategory;
79    private PreferenceCategory mSmsPrefCategory;
80    private PreferenceCategory mMmsPrefCategory;
81    private PreferenceCategory mNotificationPrefCategory;
82
83    private Preference mSmsLimitPref;
84    private Preference mSmsDeliveryReportPref;
85    private Preference mMmsLimitPref;
86    private Preference mMmsDeliveryReportPref;
87    private Preference mMmsGroupMmsPref;
88    private Preference mMmsReadReportPref;
89    private Preference mManageSimPref;
90    private Preference mClearHistoryPref;
91    private CheckBoxPreference mVibratePref;
92    private CheckBoxPreference mEnableNotificationsPref;
93    private CheckBoxPreference mMmsAutoRetrievialPref;
94    private RingtonePreference mRingtonePref;
95    private Recycler mSmsRecycler;
96    private Recycler mMmsRecycler;
97    private static final int CONFIRM_CLEAR_SEARCH_HISTORY_DIALOG = 3;
98
99    // Whether or not we are currently enabled for SMS. This field is updated in onResume to make
100    // sure we notice if the user has changed the default SMS app.
101    private boolean mIsSmsEnabled;
102
103    @Override
104    protected void onCreate(Bundle icicle) {
105        super.onCreate(icicle);
106
107        loadPrefs();
108
109        ActionBar actionBar = getActionBar();
110        actionBar.setDisplayHomeAsUpEnabled(true);
111    }
112
113    @Override
114    protected void onResume() {
115        super.onResume();
116        boolean isSmsEnabled = MmsConfig.isSmsEnabled(this);
117        if (isSmsEnabled != mIsSmsEnabled) {
118            mIsSmsEnabled = isSmsEnabled;
119            invalidateOptionsMenu();
120        }
121
122        // Since the enabled notifications pref can be changed outside of this activity,
123        // we have to reload it whenever we resume.
124        setEnabledNotificationsPref();
125        registerListeners();
126        updateSmsEnabledState();
127    }
128
129    private void updateSmsEnabledState() {
130        // Show the right pref (SMS Disabled or SMS Enabled)
131        PreferenceScreen prefRoot = (PreferenceScreen)findPreference("pref_key_root");
132        if (!mIsSmsEnabled) {
133            prefRoot.addPreference(mSmsDisabledPref);
134            prefRoot.removePreference(mSmsEnabledPref);
135        } else {
136            prefRoot.removePreference(mSmsDisabledPref);
137            prefRoot.addPreference(mSmsEnabledPref);
138        }
139
140        // Enable or Disable the settings as appropriate
141        mStoragePrefCategory.setEnabled(mIsSmsEnabled);
142        mSmsPrefCategory.setEnabled(mIsSmsEnabled);
143        mMmsPrefCategory.setEnabled(mIsSmsEnabled);
144        mNotificationPrefCategory.setEnabled(mIsSmsEnabled);
145    }
146
147    private void loadPrefs() {
148        addPreferencesFromResource(R.xml.preferences);
149
150        mSmsDisabledPref = findPreference("pref_key_sms_disabled");
151        mSmsEnabledPref = findPreference("pref_key_sms_enabled");
152
153        mStoragePrefCategory = (PreferenceCategory)findPreference("pref_key_storage_settings");
154        mSmsPrefCategory = (PreferenceCategory)findPreference("pref_key_sms_settings");
155        mMmsPrefCategory = (PreferenceCategory)findPreference("pref_key_mms_settings");
156        mNotificationPrefCategory =
157                (PreferenceCategory)findPreference("pref_key_notification_settings");
158
159        mManageSimPref = findPreference("pref_key_manage_sim_messages");
160        mSmsLimitPref = findPreference("pref_key_sms_delete_limit");
161        mSmsDeliveryReportPref = findPreference("pref_key_sms_delivery_reports");
162        mMmsDeliveryReportPref = findPreference("pref_key_mms_delivery_reports");
163        mMmsGroupMmsPref = findPreference("pref_key_mms_group_mms");
164        mMmsReadReportPref = findPreference("pref_key_mms_read_reports");
165        mMmsLimitPref = findPreference("pref_key_mms_delete_limit");
166        mClearHistoryPref = findPreference("pref_key_mms_clear_history");
167        mEnableNotificationsPref = (CheckBoxPreference) findPreference(NOTIFICATION_ENABLED);
168        mMmsAutoRetrievialPref = (CheckBoxPreference) findPreference(AUTO_RETRIEVAL);
169        mVibratePref = (CheckBoxPreference) findPreference(NOTIFICATION_VIBRATE);
170        mRingtonePref = (RingtonePreference) findPreference(NOTIFICATION_RINGTONE);
171
172        setMessagePreferences();
173    }
174
175    private void restoreDefaultPreferences() {
176        PreferenceManager.getDefaultSharedPreferences(this).edit().clear().apply();
177        setPreferenceScreen(null);
178        loadPrefs();
179        updateSmsEnabledState();
180
181        // NOTE: After restoring preferences, the auto delete function (i.e. message recycler)
182        // will be turned off by default. However, we really want the default to be turned on.
183        // Because all the prefs are cleared, that'll cause:
184        // ConversationList.runOneTimeStorageLimitCheckForLegacyMessages to get executed the
185        // next time the user runs the Messaging app and it will either turn on the setting
186        // by default, or if the user is over the limits, encourage them to turn on the setting
187        // manually.
188    }
189
190    private void setMessagePreferences() {
191        if (!MmsApp.getApplication().getTelephonyManager().hasIccCard()) {
192            // No SIM card, remove the SIM-related prefs
193            mSmsPrefCategory.removePreference(mManageSimPref);
194        }
195
196        if (!MmsConfig.getSMSDeliveryReportsEnabled()) {
197            mSmsPrefCategory.removePreference(mSmsDeliveryReportPref);
198            if (!MmsApp.getApplication().getTelephonyManager().hasIccCard()) {
199                getPreferenceScreen().removePreference(mSmsPrefCategory);
200            }
201        }
202
203        if (!MmsConfig.getMmsEnabled()) {
204            // No Mms, remove all the mms-related preferences
205            getPreferenceScreen().removePreference(mMmsPrefCategory);
206
207            mStoragePrefCategory.removePreference(findPreference("pref_key_mms_delete_limit"));
208        } else {
209            if (!MmsConfig.getMMSDeliveryReportsEnabled()) {
210                mMmsPrefCategory.removePreference(mMmsDeliveryReportPref);
211            }
212            if (!MmsConfig.getMMSReadReportsEnabled()) {
213                mMmsPrefCategory.removePreference(mMmsReadReportPref);
214            }
215            // If the phone's SIM doesn't know it's own number, disable group mms.
216            if (!MmsConfig.getGroupMmsEnabled() ||
217                    TextUtils.isEmpty(MessageUtils.getLocalNumber())) {
218                mMmsPrefCategory.removePreference(mMmsGroupMmsPref);
219            }
220        }
221
222        setEnabledNotificationsPref();
223
224        // If needed, migrate vibration setting from the previous tri-state setting stored in
225        // NOTIFICATION_VIBRATE_WHEN to the boolean setting stored in NOTIFICATION_VIBRATE.
226        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
227        if (sharedPreferences.contains(NOTIFICATION_VIBRATE_WHEN)) {
228            String vibrateWhen = sharedPreferences.
229                    getString(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN, null);
230            boolean vibrate = "always".equals(vibrateWhen);
231            SharedPreferences.Editor prefsEditor = sharedPreferences.edit();
232            prefsEditor.putBoolean(NOTIFICATION_VIBRATE, vibrate);
233            prefsEditor.remove(NOTIFICATION_VIBRATE_WHEN);  // remove obsolete setting
234            prefsEditor.apply();
235            mVibratePref.setChecked(vibrate);
236        }
237
238        mSmsRecycler = Recycler.getSmsRecycler();
239        mMmsRecycler = Recycler.getMmsRecycler();
240
241        // Fix up the recycler's summary with the correct values
242        setSmsDisplayLimit();
243        setMmsDisplayLimit();
244
245        String soundValue = sharedPreferences.getString(NOTIFICATION_RINGTONE, null);
246        setRingtoneSummary(soundValue);
247    }
248
249    private void setRingtoneSummary(String soundValue) {
250        Uri soundUri = TextUtils.isEmpty(soundValue) ? null : Uri.parse(soundValue);
251        Ringtone tone = soundUri != null ? RingtoneManager.getRingtone(this, soundUri) : null;
252        mRingtonePref.setSummary(tone != null ? tone.getTitle(this)
253                : getResources().getString(R.string.silent_ringtone));
254    }
255
256    private void setEnabledNotificationsPref() {
257        // The "enable notifications" setting is really stored in our own prefs. Read the
258        // current value and set the checkbox to match.
259        mEnableNotificationsPref.setChecked(getNotificationEnabled(this));
260    }
261
262    private void setSmsDisplayLimit() {
263        mSmsLimitPref.setSummary(
264                getString(R.string.pref_summary_delete_limit,
265                        mSmsRecycler.getMessageLimit(this)));
266    }
267
268    private void setMmsDisplayLimit() {
269        mMmsLimitPref.setSummary(
270                getString(R.string.pref_summary_delete_limit,
271                        mMmsRecycler.getMessageLimit(this)));
272    }
273
274    public boolean onCreateOptionsMenu(Menu menu) {
275        super.onCreateOptionsMenu(menu);
276        menu.clear();
277        if (mIsSmsEnabled) {
278            menu.add(0, MENU_RESTORE_DEFAULTS, 0, R.string.restore_default);
279        }
280        return true;
281    }
282
283    @Override
284    public boolean onOptionsItemSelected(MenuItem item) {
285        switch (item.getItemId()) {
286            case MENU_RESTORE_DEFAULTS:
287                restoreDefaultPreferences();
288                return true;
289
290            case android.R.id.home:
291                // The user clicked on the Messaging icon in the action bar. Take them back from
292                // wherever they came from
293                finish();
294                return true;
295        }
296        return false;
297    }
298
299    @Override
300    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
301            Preference preference) {
302        if (preference == mSmsLimitPref) {
303            new NumberPickerDialog(this,
304                    mSmsLimitListener,
305                    mSmsRecycler.getMessageLimit(this),
306                    mSmsRecycler.getMessageMinLimit(),
307                    mSmsRecycler.getMessageMaxLimit(),
308                    R.string.pref_title_sms_delete).show();
309        } else if (preference == mMmsLimitPref) {
310            new NumberPickerDialog(this,
311                    mMmsLimitListener,
312                    mMmsRecycler.getMessageLimit(this),
313                    mMmsRecycler.getMessageMinLimit(),
314                    mMmsRecycler.getMessageMaxLimit(),
315                    R.string.pref_title_mms_delete).show();
316        } else if (preference == mManageSimPref) {
317            startActivity(new Intent(this, ManageSimMessages.class));
318        } else if (preference == mClearHistoryPref) {
319            showDialog(CONFIRM_CLEAR_SEARCH_HISTORY_DIALOG);
320            return true;
321        } else if (preference == mEnableNotificationsPref) {
322            // Update the actual "enable notifications" value that is stored in secure settings.
323            enableNotifications(mEnableNotificationsPref.isChecked(), this);
324        } else if (preference == mMmsAutoRetrievialPref) {
325            if (mMmsAutoRetrievialPref.isChecked()) {
326                startMmsDownload();
327            }
328        }
329
330        return super.onPreferenceTreeClick(preferenceScreen, preference);
331    }
332
333    /**
334     * Trigger the TransactionService to download any outstanding messages.
335     */
336    private void startMmsDownload() {
337        startService(new Intent(TransactionService.ACTION_ENABLE_AUTO_RETRIEVE, null, this,
338                TransactionService.class));
339    }
340
341    NumberPickerDialog.OnNumberSetListener mSmsLimitListener =
342        new NumberPickerDialog.OnNumberSetListener() {
343            public void onNumberSet(int limit) {
344                mSmsRecycler.setMessageLimit(MessagingPreferenceActivity.this, limit);
345                setSmsDisplayLimit();
346            }
347    };
348
349    NumberPickerDialog.OnNumberSetListener mMmsLimitListener =
350        new NumberPickerDialog.OnNumberSetListener() {
351            public void onNumberSet(int limit) {
352                mMmsRecycler.setMessageLimit(MessagingPreferenceActivity.this, limit);
353                setMmsDisplayLimit();
354            }
355    };
356
357    @Override
358    protected Dialog onCreateDialog(int id) {
359        switch (id) {
360            case CONFIRM_CLEAR_SEARCH_HISTORY_DIALOG:
361                return new AlertDialog.Builder(MessagingPreferenceActivity.this)
362                    .setTitle(R.string.confirm_clear_search_title)
363                    .setMessage(R.string.confirm_clear_search_text)
364                    .setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
365                        public void onClick(DialogInterface dialog, int which) {
366                            SearchRecentSuggestions recent =
367                                ((MmsApp)getApplication()).getRecentSuggestions();
368                            if (recent != null) {
369                                recent.clearHistory();
370                            }
371                            dialog.dismiss();
372                        }
373                    })
374                    .setNegativeButton(android.R.string.cancel, null)
375                    .setIconAttribute(android.R.attr.alertDialogIcon)
376                    .create();
377        }
378        return super.onCreateDialog(id);
379    }
380
381    public static boolean getNotificationEnabled(Context context) {
382        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
383        boolean notificationsEnabled =
384            prefs.getBoolean(MessagingPreferenceActivity.NOTIFICATION_ENABLED, true);
385        return notificationsEnabled;
386    }
387
388    public static void enableNotifications(boolean enabled, Context context) {
389        // Store the value of notifications in SharedPreferences
390        SharedPreferences.Editor editor =
391            PreferenceManager.getDefaultSharedPreferences(context).edit();
392
393        editor.putBoolean(MessagingPreferenceActivity.NOTIFICATION_ENABLED, enabled);
394
395        editor.apply();
396    }
397
398    private void registerListeners() {
399        mRingtonePref.setOnPreferenceChangeListener(this);
400    }
401
402    public boolean onPreferenceChange(Preference preference, Object newValue) {
403        boolean result = false;
404        if (preference == mRingtonePref) {
405            setRingtoneSummary((String)newValue);
406            result = true;
407        }
408        return result;
409    }
410
411    // For the group mms feature to be enabled, the following must be true:
412    //  1. the feature is enabled in mms_config.xml (currently on by default)
413    //  2. the feature is enabled in the mms settings page
414    //  3. the SIM knows its own phone number
415    public static boolean getIsGroupMmsEnabled(Context context) {
416        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
417        boolean groupMmsPrefOn = prefs.getBoolean(
418                MessagingPreferenceActivity.GROUP_MMS_MODE, true);
419        return MmsConfig.getGroupMmsEnabled() &&
420                groupMmsPrefOn &&
421                !TextUtils.isEmpty(MessageUtils.getLocalNumber());
422    }
423}
424