Home | History | Annotate | Download | only in settings
      1 /*******************************************************************************
      2  *      Copyright (C) 2014 Google Inc.
      3  *      Licensed to 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.mail.ui.settings;
     19 
     20 import android.app.AlertDialog;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.DialogInterface.OnClickListener;
     24 import android.os.AsyncTask;
     25 import android.os.Bundle;
     26 import android.preference.CheckBoxPreference;
     27 import android.preference.ListPreference;
     28 import android.preference.Preference;
     29 import android.preference.Preference.OnPreferenceChangeListener;
     30 import android.provider.SearchRecentSuggestions;
     31 import android.view.Menu;
     32 import android.view.MenuInflater;
     33 import android.view.MenuItem;
     34 import android.widget.Toast;
     35 
     36 import com.android.mail.preferences.MailPrefs;
     37 import com.android.mail.preferences.MailPrefs.PreferenceKeys;
     38 import com.android.mail.providers.SuggestionsProvider;
     39 import com.android.mail.providers.UIProvider.AutoAdvance;
     40 import com.android.mail.utils.LogUtils;
     41 import com.android.mail.R;
     42 import com.google.common.annotations.VisibleForTesting;
     43 
     44 /**
     45  * This fragment shows general app preferences.
     46  */
     47 public class GeneralPrefsFragment extends MailPreferenceFragment
     48         implements OnClickListener, OnPreferenceChangeListener {
     49 
     50     // Keys used to reference pref widgets which don't map directly to preference entries
     51     static final String AUTO_ADVANCE_WIDGET = "auto-advance-widget";
     52 
     53     static final String CALLED_FROM_TEST = "called-from-test";
     54 
     55     // Category for removal actions
     56     protected static final String REMOVAL_ACTIONS_GROUP = "removal-actions-group";
     57 
     58     protected MailPrefs mMailPrefs;
     59 
     60     private AlertDialog mClearSearchHistoryDialog;
     61 
     62     private ListPreference mAutoAdvance;
     63     private static final int[] AUTO_ADVANCE_VALUES = {
     64             AutoAdvance.NEWER,
     65             AutoAdvance.OLDER,
     66             AutoAdvance.LIST
     67     };
     68 
     69     @Override
     70     public void onCreate(Bundle savedInstanceState) {
     71         super.onCreate(savedInstanceState);
     72 
     73         setHasOptionsMenu(true);
     74 
     75         mMailPrefs = MailPrefs.get(getActivity());
     76 
     77         // Set the shared prefs name to use prefs auto-persist behavior by default.
     78         // Any pref more complex than the default (say, involving migration), should set
     79         // "persistent=false" in the XML and manually handle preference initialization and change.
     80         getPreferenceManager()
     81                 .setSharedPreferencesName(mMailPrefs.getSharedPreferencesName());
     82 
     83         addPreferencesFromResource(R.xml.general_preferences);
     84 
     85         mAutoAdvance = (ListPreference) findPreference(AUTO_ADVANCE_WIDGET);
     86     }
     87 
     88     @Override
     89     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
     90         /*
     91          * We deliberately do not call super because our menu includes the parent's menu options to
     92          * allow custom ordering.
     93          */
     94         menu.clear();
     95         inflater.inflate(R.menu.general_prefs_fragment_menu, menu);
     96     }
     97 
     98     @Override
     99     public boolean onOptionsItemSelected(MenuItem item) {
    100         final int itemId = item.getItemId();
    101         if (itemId == R.id.clear_search_history_menu_item) {
    102             clearSearchHistory();
    103             return true;
    104         } else if (itemId == R.id.clear_picture_approvals_menu_item) {
    105             clearDisplayImages();
    106             return true;
    107         }
    108 
    109         return super.onOptionsItemSelected(item);
    110     }
    111 
    112     @Override
    113     public boolean onPreferenceChange(Preference preference, Object newValue) {
    114         if (getActivity() == null) {
    115             // Monkeys cause bad things. This callback may be delayed if for some reason the
    116             // preference screen was closed really quickly - just bail then.
    117             return false;
    118         }
    119 
    120         final String key = preference.getKey();
    121 
    122         if (PreferenceKeys.REMOVAL_ACTION.equals(key)) {
    123             final String removalAction = newValue.toString();
    124             mMailPrefs.setRemovalAction(removalAction);
    125             updateListSwipeTitle(removalAction);
    126         } else if (AUTO_ADVANCE_WIDGET.equals(key)) {
    127             final int prefsAutoAdvanceMode =
    128                     AUTO_ADVANCE_VALUES[mAutoAdvance.findIndexOfValue((String) newValue)];
    129             mMailPrefs.setAutoAdvanceMode(prefsAutoAdvanceMode);
    130         } else if (!PreferenceKeys.CONVERSATION_LIST_SWIPE.equals(key) &&
    131                 !PreferenceKeys.SHOW_SENDER_IMAGES.equals(key) &&
    132                 !PreferenceKeys.DEFAULT_REPLY_ALL.equals(key) &&
    133                 !PreferenceKeys.CONVERSATION_OVERVIEW_MODE.equals(key) &&
    134                 !PreferenceKeys.CONFIRM_DELETE.equals(key) &&
    135                 !PreferenceKeys.CONFIRM_ARCHIVE.equals(key) &&
    136                 !PreferenceKeys.CONFIRM_SEND.equals(key)) {
    137             return false;
    138         }
    139 
    140         return true;
    141     }
    142 
    143     private void clearDisplayImages() {
    144         final ClearPictureApprovalsDialogFragment fragment =
    145                 ClearPictureApprovalsDialogFragment.newInstance();
    146         fragment.show(getActivity().getFragmentManager(),
    147                 ClearPictureApprovalsDialogFragment.FRAGMENT_TAG);
    148     }
    149 
    150     private void clearSearchHistory() {
    151         mClearSearchHistoryDialog = new AlertDialog.Builder(getActivity())
    152                 .setMessage(R.string.clear_history_dialog_message)
    153                 .setTitle(R.string.clear_history_dialog_title)
    154                 .setIconAttribute(android.R.attr.alertDialogIcon)
    155                 .setPositiveButton(R.string.clear, this)
    156                 .setNegativeButton(R.string.cancel, this)
    157                 .show();
    158     }
    159 
    160 
    161     @Override
    162     public void onClick(DialogInterface dialog, int which) {
    163         if (dialog.equals(mClearSearchHistoryDialog)) {
    164             if (which == DialogInterface.BUTTON_POSITIVE) {
    165                 final Context context = getActivity();
    166                 // Clear the history in the background, as it causes a disk
    167                 // write.
    168                 new AsyncTask<Void, Void, Void>() {
    169                     @Override
    170                     protected Void doInBackground(Void... params) {
    171                         final String authority = context.getString(
    172                                 com.android.mail.R.string.suggestions_authority);
    173                         final SearchRecentSuggestions suggestions =
    174                                 new SearchRecentSuggestions(context, authority,
    175                                         SuggestionsProvider.MODE);
    176                         suggestions.clearHistory();
    177                         return null;
    178                     }
    179                 }.execute();
    180                 Toast.makeText(getActivity(), R.string.search_history_cleared, Toast.LENGTH_SHORT)
    181                         .show();
    182             }
    183         }
    184     }
    185 
    186     @Override
    187     public void onStop() {
    188         super.onStop();
    189         if (mClearSearchHistoryDialog != null && mClearSearchHistoryDialog.isShowing()) {
    190             mClearSearchHistoryDialog.dismiss();
    191         }
    192     }
    193 
    194     @Override
    195     public void onResume() {
    196         super.onResume();
    197 
    198         // Manually initialize the preference views that require massaging. Prefs that require
    199         // massaging include:
    200         //  1. a prefs UI control that does not map 1:1 to storage
    201         //  2. a pref that must obtain its initial value from migrated storage, and for which we
    202         //     don't want to always persist a migrated value
    203         final int autoAdvanceModeIndex = prefValueToWidgetIndex(AUTO_ADVANCE_VALUES,
    204                 mMailPrefs.getAutoAdvanceMode(), AutoAdvance.DEFAULT);
    205         mAutoAdvance.setValueIndex(autoAdvanceModeIndex);
    206 
    207         final String removalAction = mMailPrefs.getRemovalAction(supportsArchive());
    208         updateListSwipeTitle(removalAction);
    209 
    210         listenForPreferenceChange(
    211                 PreferenceKeys.REMOVAL_ACTION,
    212                 PreferenceKeys.CONVERSATION_LIST_SWIPE,
    213                 PreferenceKeys.SHOW_SENDER_IMAGES,
    214                 PreferenceKeys.DEFAULT_REPLY_ALL,
    215                 PreferenceKeys.CONVERSATION_OVERVIEW_MODE,
    216                 AUTO_ADVANCE_WIDGET,
    217                 PreferenceKeys.CONFIRM_DELETE,
    218                 PreferenceKeys.CONFIRM_ARCHIVE,
    219                 PreferenceKeys.CONFIRM_SEND
    220         );
    221     }
    222 
    223     protected boolean supportsArchive() {
    224         return true;
    225     }
    226 
    227     /**
    228      * Converts the prefs value into an index useful for configuring the UI widget, falling back to
    229      * the default value if the value from the prefs can't be found for some reason. If neither can
    230      * be found, it throws an {@link java.lang.IllegalArgumentException}
    231      *
    232      * @param conversionArray An array of prefs values, in widget order
    233      * @param prefValue Value of the preference
    234      * @param defaultValue Default value, as a fallback if we can't map the real value
    235      * @return Index of the entry (or fallback) in the conversion array
    236      */
    237     @VisibleForTesting
    238     static int prefValueToWidgetIndex(int[] conversionArray, int prefValue, int defaultValue) {
    239         for (int i = 0; i < conversionArray.length; i++) {
    240             if (conversionArray[i] == prefValue) {
    241                 return i;
    242             }
    243         }
    244         LogUtils.e(LogUtils.TAG, "Can't map preference value " + prefValue);
    245         for (int i = 0; i < conversionArray.length; i++) {
    246             if (conversionArray[i] == defaultValue) {
    247                 return i;
    248             }
    249         }
    250         throw new IllegalArgumentException("Can't map default preference value " + prefValue);
    251     }
    252 
    253     private void listenForPreferenceChange(String... keys) {
    254         for (String key : keys) {
    255             Preference p = findPreference(key);
    256             if (p != null) {
    257                 p.setOnPreferenceChangeListener(this);
    258             }
    259         }
    260     }
    261 
    262     private void updateListSwipeTitle(final String removalAction) {
    263         final CheckBoxPreference listSwipePreference = (CheckBoxPreference)
    264                 findPreference(MailPrefs.PreferenceKeys.CONVERSATION_LIST_SWIPE);
    265         listSwipePreference.setTitle(MailPrefs.RemovalActions.DELETE.equals(removalAction) ?
    266                 R.string.preference_swipe_title_delete : R.string.preference_swipe_title_archive);
    267     }
    268 }
    269