Home | History | Annotate | Download | only in setup
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.email.activity.setup;
     18 
     19 import android.app.ActionBar;
     20 import android.app.Activity;
     21 import android.content.ContentUris;
     22 import android.content.ContentValues;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.res.Resources;
     26 import android.net.Uri;
     27 import android.os.Bundle;
     28 import android.preference.CheckBoxPreference;
     29 import android.preference.ListPreference;
     30 import android.preference.Preference;
     31 import android.preference.Preference.OnPreferenceChangeListener;
     32 import android.preference.PreferenceActivity;
     33 import android.view.MenuItem;
     34 
     35 import com.android.email.R;
     36 import com.android.emailcommon.Logging;
     37 import com.android.emailcommon.provider.Account;
     38 import com.android.emailcommon.provider.EmailContent.MailboxColumns;
     39 import com.android.emailcommon.provider.Mailbox;
     40 import com.android.emailcommon.provider.Policy;
     41 import com.android.emailcommon.utility.EmailAsyncTask;
     42 import com.android.emailcommon.utility.Utility;
     43 import com.android.mail.utils.LogUtils;
     44 import com.google.common.base.Preconditions;
     45 
     46 import java.util.Arrays;
     47 
     48 /**
     49  * "Mailbox settings" activity.
     50  *
     51  * It's used to update per-mailbox sync settings.  It normally updates Mailbox settings, unless
     52  * the target mailbox is Inbox, in which case it updates Account settings instead.
     53  *
     54  * All changes made by the user will not be immediately saved to the database, as changing the
     55  * sync window may result in removal of messages.  Instead, we only save to the database in {@link
     56  * #onDestroy()}, unless it's called for configuration changes.
     57  */
     58 public class MailboxSettings extends PreferenceActivity {
     59     private static final String EXTRA_MAILBOX_ID = "MAILBOX_ID";
     60     private static final String BUNDLE_MAILBOX = "MailboxSettings.mailbox";
     61     private static final String BUNDLE_MAX_LOOKBACK = "MailboxSettings.maxLookback";
     62     private static final String BUNDLE_SYNC_ENABLED_VALUE = "MailboxSettings.syncEnabled";
     63     private static final String BUNDLE_SYNC_WINDOW_VALUE = "MailboxSettings.syncWindow";
     64 
     65     private static final String PREF_SYNC_ENABLED_KEY = "sync_enabled";
     66     private static final String PREF_SYNC_WINDOW_KEY = "sync_window";
     67 
     68     /** Projection for loading an account's policy key. */
     69     private static final String[] POLICY_KEY_PROJECTION = { Account.POLICY_KEY };
     70     private static final int POLICY_KEY_COLUMN = 0;
     71 
     72     /** Projection for loading the max email lookback. */
     73     private static final String[] MAX_EMAIL_LOOKBACK_PROJECTION = { Policy.MAX_EMAIL_LOOKBACK };
     74     private static final int MAX_EMAIL_LOOKBACK_COLUMN = 0;
     75 
     76     private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
     77 
     78     private Mailbox mMailbox;
     79     /** The maximum lookback allowed for this mailbox, or 0 if no max. */
     80     private int mMaxLookback;
     81 
     82     private CheckBoxPreference mSyncEnabledPref;
     83     private ListPreference mSyncLookbackPref;
     84 
     85     /**
     86      * Starts the activity for a mailbox.
     87      */
     88     public static final void start(Activity parent, long mailboxId) {
     89         Intent i = new Intent(parent, MailboxSettings.class);
     90         i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
     91         parent.startActivity(i);
     92     }
     93 
     94     @Override
     95     protected void onCreate(Bundle savedInstanceState) {
     96         super.onCreate(savedInstanceState);
     97 
     98         final long mailboxId = getIntent().getLongExtra(EXTRA_MAILBOX_ID, Mailbox.NO_MAILBOX);
     99         if (mailboxId == Mailbox.NO_MAILBOX) {
    100             finish();
    101             return;
    102         }
    103 
    104         addPreferencesFromResource(R.xml.mailbox_preferences);
    105 
    106         mSyncEnabledPref = (CheckBoxPreference) findPreference(PREF_SYNC_ENABLED_KEY);
    107         mSyncLookbackPref = (ListPreference) findPreference(PREF_SYNC_WINDOW_KEY);
    108 
    109         mSyncLookbackPref.setOnPreferenceChangeListener(mPreferenceChanged);
    110 
    111         if (savedInstanceState != null) {
    112             mMailbox = savedInstanceState.getParcelable(BUNDLE_MAILBOX);
    113             mMaxLookback = savedInstanceState.getInt(BUNDLE_MAX_LOOKBACK);
    114             mSyncEnabledPref.setChecked(savedInstanceState.getBoolean(BUNDLE_SYNC_ENABLED_VALUE));
    115             mSyncLookbackPref.setValue(savedInstanceState.getString(BUNDLE_SYNC_WINDOW_VALUE));
    116             onDataLoaded();
    117         } else {
    118             // Make them disabled until we load data
    119             enablePreferences(false);
    120             new LoadMailboxTask(mailboxId).executeParallel((Void[]) null);
    121         }
    122 
    123         // Always show "app up" as we expect our parent to be an Email activity.
    124         ActionBar actionBar = getActionBar();
    125         if (actionBar != null) {
    126             actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
    127         }
    128     }
    129 
    130     private void enablePreferences(boolean enabled) {
    131         mSyncEnabledPref.setEnabled(enabled);
    132         mSyncLookbackPref.setEnabled(enabled);
    133     }
    134 
    135     @Override
    136     protected void onSaveInstanceState(Bundle outState) {
    137         super.onSaveInstanceState(outState);
    138         outState.putParcelable(BUNDLE_MAILBOX, mMailbox);
    139         outState.putInt(BUNDLE_MAX_LOOKBACK, mMaxLookback);
    140         outState.putBoolean(BUNDLE_SYNC_ENABLED_VALUE, mSyncEnabledPref.isChecked());
    141         outState.putString(BUNDLE_SYNC_WINDOW_VALUE, mSyncLookbackPref.getValue());
    142     }
    143 
    144     /**
    145      * We save all the settings in onDestroy, *unless it's for configuration changes*.
    146      */
    147     @Override
    148     protected void onDestroy() {
    149         mTaskTracker.cancellAllInterrupt();
    150         if (!isChangingConfigurations()) {
    151             saveToDatabase();
    152         }
    153         super.onDestroy();
    154     }
    155 
    156     /**
    157      * Loads {@link #mMailbox} and {@link #mMaxLookback} from DB.
    158      */
    159     private class LoadMailboxTask extends EmailAsyncTask<Void, Void, Void> {
    160         private final long mMailboxId;
    161 
    162         public LoadMailboxTask(long mailboxId) {
    163             super(mTaskTracker);
    164             mMailboxId = mailboxId;
    165         }
    166 
    167         @Override
    168         protected Void doInBackground(Void... params) {
    169             final Context c = MailboxSettings.this;
    170             mMailbox = Mailbox.restoreMailboxWithId(c, mMailboxId);
    171             mMaxLookback = 0;
    172             if (mMailbox != null) {
    173                 // Get the max lookback from our policy, if we have one.
    174                 final Long policyKey = Utility.getFirstRowLong(c, ContentUris.withAppendedId(
    175                         Account.CONTENT_URI, mMailbox.mAccountKey), POLICY_KEY_PROJECTION,
    176                         null, null, null, POLICY_KEY_COLUMN);
    177                 if (policyKey != null) {
    178                     mMaxLookback = Utility.getFirstRowInt(c, ContentUris.withAppendedId(
    179                             Policy.CONTENT_URI, policyKey), MAX_EMAIL_LOOKBACK_PROJECTION,
    180                             null, null, null, MAX_EMAIL_LOOKBACK_COLUMN, 0);
    181                 }
    182             }
    183             return null;
    184         }
    185 
    186         @Override
    187         protected void onSuccess(Void result) {
    188             if (mMailbox == null) {
    189                 finish(); // Account or mailbox removed.
    190                 return;
    191             }
    192             mSyncEnabledPref.setChecked(mMailbox.mSyncInterval != 0);
    193             mSyncLookbackPref.setValue(String.valueOf(mMailbox.mSyncLookback));
    194             onDataLoaded();
    195             if (mMailbox.mType != Mailbox.TYPE_DRAFTS) {
    196                 enablePreferences(true);
    197             }
    198         }
    199     }
    200 
    201     /**
    202      * Setup the entries and entry values for the sync lookback preference
    203      * @param context the caller's context
    204      * @param pref a ListPreference to be set up
    205      * @param maxLookback The maximum lookback allowed, or 0 if no max.
    206      * @param showWithDefault Whether to show the version with default, or without.
    207      */
    208     public static void setupLookbackPreferenceOptions(final Context context,
    209             final ListPreference pref, final int maxLookback, final boolean showWithDefault) {
    210         final Resources resources = context.getResources();
    211         // Load the complete list of entries/values
    212         CharSequence[] entries;
    213         CharSequence[] values;
    214         final int offset;
    215         if (showWithDefault) {
    216             entries = resources.getTextArray(
    217                     R.array.account_settings_mail_window_entries_with_default);
    218             values = resources.getTextArray(
    219                     R.array.account_settings_mail_window_values_with_default);
    220             offset = 1;
    221         } else {
    222             entries = resources.getTextArray(R.array.account_settings_mail_window_entries);
    223             values = resources.getTextArray(R.array.account_settings_mail_window_values);
    224             offset = 0;
    225         }
    226         // If we have a maximum lookback policy, enforce it
    227         if (maxLookback > 0) {
    228             final int size = maxLookback + offset;
    229             entries = Arrays.copyOf(entries, size);
    230             values = Arrays.copyOf(values, size);
    231         }
    232         // Set up the preference
    233         pref.setEntries(entries);
    234         pref.setEntryValues(values);
    235         pref.setSummary(pref.getEntry());
    236     }
    237 
    238     /**
    239      * Called when {@link #mMailbox} is loaded (either by the async task or from the saved state).
    240      */
    241     private void onDataLoaded() {
    242         Preconditions.checkNotNull(mMailbox);
    243 
    244         // Update the title with the mailbox name.
    245         final ActionBar actionBar = getActionBar();
    246         final String mailboxName = mMailbox.mDisplayName;
    247         if (actionBar != null) {
    248             actionBar.setTitle(mailboxName);
    249             actionBar.setSubtitle(getString(R.string.mailbox_settings_activity_title));
    250         } else {
    251             setTitle(getString(R.string.mailbox_settings_activity_title_with_mailbox, mailboxName));
    252         }
    253 
    254         setupLookbackPreferenceOptions(this, mSyncLookbackPref, mMaxLookback, true);
    255     }
    256 
    257 
    258     private final OnPreferenceChangeListener mPreferenceChanged = new OnPreferenceChangeListener() {
    259         @Override
    260         public boolean onPreferenceChange(Preference preference, Object newValue) {
    261             mSyncLookbackPref.setValue((String) newValue);
    262             mSyncLookbackPref.setSummary(mSyncLookbackPref.getEntry());
    263             return false;
    264         }
    265     };
    266 
    267     /**
    268      * Save changes to the database.
    269      *
    270      * Note it's called from {@link #onDestroy()}, which is called on the UI thread where we're not
    271      * allowed to touch the database, so it uses {@link EmailAsyncTask} to do the save on a bg
    272      * thread. This unfortunately means there's a chance that the app gets killed before the save is
    273      * finished.
    274      */
    275     private void saveToDatabase() {
    276         final int syncInterval = mSyncEnabledPref.isChecked() ? 1 : 0;
    277         final int syncLookback = Integer.valueOf(mSyncLookbackPref.getValue());
    278 
    279         final boolean syncIntervalChanged = syncInterval != mMailbox.mSyncInterval;
    280         final boolean syncLookbackChanged = syncLookback != mMailbox.mSyncLookback;
    281 
    282         // Only save if a preference has changed value.
    283         if (syncIntervalChanged || syncLookbackChanged) {
    284             LogUtils.i(Logging.LOG_TAG, "Saving mailbox settings...");
    285             enablePreferences(false);
    286 
    287             final long id = mMailbox.mId;
    288             final Context context = getApplicationContext();
    289 
    290             new EmailAsyncTask<Void, Void, Void> (null /* no cancel */) {
    291                 @Override
    292                 protected Void doInBackground(Void... params) {
    293                     final ContentValues cv = new ContentValues(2);
    294                     final Uri uri;
    295                     if (syncIntervalChanged) {
    296                         cv.put(MailboxColumns.SYNC_INTERVAL, syncInterval);
    297                     }
    298                     if (syncLookbackChanged) {
    299                         cv.put(MailboxColumns.SYNC_LOOKBACK, syncLookback);
    300                     }
    301                     uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, id);
    302                     context.getContentResolver().update(uri, cv, null, null);
    303 
    304                     LogUtils.i(Logging.LOG_TAG, "Saved: " + uri);
    305                     return null;
    306                 }
    307 
    308                 @Override
    309                 protected void onSuccess(Void result) {
    310                     // must be called on the ui thread
    311                     //***
    312                     //RefreshManager.getInstance(context).refreshMessageList(account.mId,
    313                     //        mailbox.mId, true);
    314                 }
    315             }.executeSerial((Void [])null);
    316         }
    317     }
    318 
    319     @Override
    320     public boolean onOptionsItemSelected(MenuItem item) {
    321         if (item.getItemId() == android.R.id.home) {
    322             onBackPressed();
    323             return true;
    324         }
    325         return super.onOptionsItemSelected(item);
    326     }
    327 }
    328