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