MailboxSettings.java revision 6be8cceaddb93f5f9467854c8d11fa518e95c52b
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 17package com.android.email.activity.setup; 18 19import android.app.ActionBar; 20import android.app.Activity; 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Context; 24import android.content.Intent; 25import android.net.Uri; 26import android.os.Bundle; 27import android.preference.ListPreference; 28import android.preference.Preference; 29import android.preference.Preference.OnPreferenceChangeListener; 30import android.preference.PreferenceActivity; 31import android.util.Log; 32import android.view.MenuItem; 33 34import com.android.email.Email; 35import com.android.email.FolderProperties; 36import com.android.email.R; 37import com.android.email.RefreshManager; 38import com.android.emailcommon.Logging; 39import com.android.emailcommon.provider.Account; 40import com.android.emailcommon.provider.EmailContent.AccountColumns; 41import com.android.emailcommon.provider.EmailContent.MailboxColumns; 42import com.android.emailcommon.provider.Mailbox; 43import com.android.emailcommon.utility.EmailAsyncTask; 44import com.google.common.base.Objects; 45import com.google.common.base.Preconditions; 46 47/** 48 * "Mailbox settings" activity. 49 * 50 * It's used to update per-mailbox sync settings. It normally updates Mailbox settings, unless 51 * the target mailbox is Inbox, in which case it updates Account settings instead. 52 * 53 * All changes made by the user will not be immediately saved to the database, as changing the 54 * sync window may result in removal of messages. Instead, we only save to the database in {@link 55 * #onDestroy()}, unless it's called for configuration changes. 56 */ 57public class MailboxSettings extends PreferenceActivity { 58 private static final String EXTRA_MAILBOX_ID = "MAILBOX_ID"; 59 private static final String BUNDLE_ACCOUNT = "MailboxSettings.account"; 60 private static final String BUNDLE_MAILBOX = "MailboxSettings.mailbox"; 61 private static final String BUNDLE_NEEDS_SAVE = "MailboxSettings.needsSave"; 62 63 private static final String PREF_CHECK_FREQUENCY_KEY = "check_frequency"; 64 private static final String PREF_SYNC_WINDOW_KEY = "sync_window"; 65 66 private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker(); 67 68 // Account and Mailbox -- directly loaded by LoadMailboxTask 69 private Account mAccount; 70 private Mailbox mMailbox; 71 private boolean mNeedsSave; 72 73 private ListPreference mSyncIntervalPref; 74 private ListPreference mSyncLookbackPref; 75 76 /** 77 * Starts the activity for a mailbox. 78 */ 79 public static final void start(Activity parent, long mailboxId) { 80 Intent i = new Intent(parent, MailboxSettings.class); 81 i.putExtra(EXTRA_MAILBOX_ID, mailboxId); 82 parent.startActivity(i); 83 } 84 85 @Override 86 protected void onCreate(Bundle savedInstanceState) { 87 super.onCreate(savedInstanceState); 88 89 final long mailboxId = getIntent().getLongExtra(EXTRA_MAILBOX_ID, Mailbox.NO_MAILBOX); 90 if (mailboxId == Mailbox.NO_MAILBOX) { 91 finish(); 92 return; 93 } 94 95 addPreferencesFromResource(R.xml.mailbox_preferences); 96 97 mSyncIntervalPref = (ListPreference) findPreference(PREF_CHECK_FREQUENCY_KEY); 98 mSyncLookbackPref = (ListPreference) findPreference(PREF_SYNC_WINDOW_KEY); 99 100 mSyncIntervalPref.setOnPreferenceChangeListener(mPreferenceChanged); 101 mSyncLookbackPref.setOnPreferenceChangeListener(mPreferenceChanged); 102 103 // Make them disabled until we load data 104 enablePreferences(false); 105 106 if (savedInstanceState != null) { 107 mAccount = savedInstanceState.getParcelable(BUNDLE_ACCOUNT); 108 mMailbox = savedInstanceState.getParcelable(BUNDLE_MAILBOX); 109 mNeedsSave = savedInstanceState.getBoolean(BUNDLE_NEEDS_SAVE); 110 } 111 if (mAccount == null) { 112 new LoadMailboxTask(mailboxId).executeParallel((Void[]) null); 113 } else { 114 onDataLoaded(); 115 } 116 117 // Always show "app up" as we expect our parent to be an Email activity. 118 ActionBar actionBar = getActionBar(); 119 if (actionBar != null) { 120 actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP); 121 } 122 } 123 124 private void enablePreferences(boolean enabled) { 125 mSyncIntervalPref.setEnabled(enabled); 126 mSyncLookbackPref.setEnabled(enabled); 127 } 128 129 @Override 130 protected void onSaveInstanceState(Bundle outState) { 131 super.onSaveInstanceState(outState); 132 outState.putParcelable(BUNDLE_ACCOUNT, mAccount); 133 outState.putParcelable(BUNDLE_MAILBOX, mMailbox); 134 outState.putBoolean(BUNDLE_NEEDS_SAVE, mNeedsSave); 135 } 136 137 /** 138 * We save all the settings in onDestroy, *unless it's for configuration changes*. 139 */ 140 @Override 141 protected void onDestroy() { 142 mTaskTracker.cancellAllInterrupt(); 143 if (!isChangingConfigurations()) { 144 saveToDatabase(); 145 } 146 super.onDestroy(); 147 } 148 149 /** 150 * Loads {@link #mAccount} and {@link #mMailbox}. 151 */ 152 private class LoadMailboxTask extends EmailAsyncTask<Void, Void, Void> { 153 private final long mMailboxId; 154 155 public LoadMailboxTask(long mailboxId) { 156 super(mTaskTracker); 157 mMailboxId = mailboxId; 158 } 159 160 @Override 161 protected Void doInBackground(Void... params) { 162 final Context c = MailboxSettings.this; 163 mMailbox = Mailbox.restoreMailboxWithId(c, mMailboxId); 164 if (mMailbox != null) { 165 mAccount = Account.restoreAccountWithId(c, mMailbox.mAccountKey); 166 } 167 return null; 168 } 169 170 @Override 171 protected void onSuccess(Void result) { 172 if ((mAccount == null) || (mMailbox == null)) { 173 finish(); // Account or mailbox removed. 174 return; 175 } 176 onDataLoaded(); 177 } 178 } 179 180 /** 181 * Called when {@link #mAccount} and {@link #mMailbox} are loaded (either by the async task 182 * or from the saved state). 183 */ 184 private void onDataLoaded() { 185 Preconditions.checkNotNull(mAccount); 186 Preconditions.checkNotNull(mMailbox); 187 188 // Update the title with the mailbox name. 189 ActionBar actionBar = getActionBar(); 190 String mailboxName = FolderProperties.getInstance(this).getDisplayName(mMailbox); 191 if (actionBar != null) { 192 actionBar.setTitle(mailboxName); 193 actionBar.setSubtitle(getString(R.string.mailbox_settings_activity_title)); 194 } else { 195 setTitle(getString(R.string.mailbox_settings_activity_title_with_mailbox, mailboxName)); 196 } 197 198 199 // Special case: If setting inbox, don't show "Use account's default". 200 if (mMailbox.mType == Mailbox.TYPE_INBOX) { 201 mSyncLookbackPref.setEntries(R.array.account_settings_mail_window_entries); 202 mSyncLookbackPref.setEntryValues(R.array.account_settings_mail_window_values); 203 } 204 205 // Set default value & update summary 206 mSyncIntervalPref.setValue(String.valueOf(getSyncInterval())); 207 mSyncLookbackPref.setValue(String.valueOf(getSyncLookback())); 208 209 updatePreferenceSummary(); 210 211 // Make then enabled 212 enablePreferences(true); 213 214 } 215 216 private void updatePreferenceSummary() { 217 mSyncIntervalPref.setSummary(mSyncIntervalPref.getEntry()); 218 mSyncLookbackPref.setSummary(mSyncLookbackPref.getEntry()); 219 } 220 221 /** 222 * @return current sync interval setting from the objects 223 */ 224 private int getSyncInterval() { 225 if (mMailbox.mType == Mailbox.TYPE_INBOX) { 226 return mAccount.mSyncInterval; 227 } else { 228 if (mMailbox.mSyncInterval == 0) { 229 // 0 is the default value, and it means "don't sync" (for non-inbox mailboxes) 230 return Mailbox.CHECK_INTERVAL_NEVER; 231 } 232 return mMailbox.mSyncInterval; 233 } 234 } 235 236 /** 237 * @return current sync lookback setting from the objects 238 */ 239 private int getSyncLookback() { 240 if (mMailbox.mType == Mailbox.TYPE_INBOX) { 241 return mAccount.mSyncLookback; 242 } else { 243 // Here, 0 is valid and means "use the account default sync window". 244 return mMailbox.mSyncLookback; 245 } 246 } 247 248 private final OnPreferenceChangeListener mPreferenceChanged = new OnPreferenceChangeListener() { 249 @Override 250 public boolean onPreferenceChange(Preference preference, Object newValue) { 251 final ListPreference lp = (ListPreference) preference; 252 if (Objects.equal(lp.getValue(), newValue)) { 253 return false; 254 } 255 mNeedsSave = true; 256 if (Email.DEBUG) { 257 Log.i(Logging.LOG_TAG, "Setting changed"); 258 } 259 // In order to set the current entry to the summary, we need to udpate the value 260 // manually, rather than letting the framework do that (by returning true). 261 lp.setValue((String) newValue); 262 updatePreferenceSummary(); 263 updateObjects(); 264 return false; 265 } 266 }; 267 268 /** 269 * Updates {@link #mAccount}/{@link #mMailbox}, but doesn't save to the database yet. 270 */ 271 private void updateObjects() { 272 final int syncInterval = Integer.valueOf(mSyncIntervalPref.getValue()); 273 final int syncLookback = Integer.valueOf(mSyncLookbackPref.getValue()); 274 if (Email.DEBUG) { 275 Log.i(Logging.LOG_TAG, "Updating object: " + syncInterval + "," + syncLookback); 276 } 277 if (mMailbox.mType == Mailbox.TYPE_INBOX) { 278 mAccount.mSyncInterval = syncInterval; 279 mAccount.mSyncLookback = syncLookback; 280 } else { 281 mMailbox.mSyncInterval = syncInterval; 282 mMailbox.mSyncLookback = syncLookback; 283 } 284 } 285 286 /** 287 * Save changes to the database. 288 * 289 * Note it's called from {@link #onDestroy()}, which is called on the UI thread where we're not 290 * allowed to touch the database, so it uses {@link EmailAsyncTask} to do the save on a bg 291 * thread. This unfortunately means there's a chance that the app gets killed before the save is 292 * finished. 293 */ 294 private void saveToDatabase() { 295 if (!mNeedsSave) { 296 return; 297 } 298 Log.i(Logging.LOG_TAG, "Saving mailbox settings..."); 299 enablePreferences(false); 300 301 // Since the activity will be destroyed... 302 // Create local references (Although it's really okay to touch members of a destroyed 303 // activity...) 304 final Account account = mAccount; 305 final Mailbox mailbox = mMailbox; 306 final Context context = getApplicationContext(); 307 308 new EmailAsyncTask<Void, Void, Void> (null /* no cancel */) { 309 @Override 310 protected Void doInBackground(Void... params) { 311 final ContentValues cv = new ContentValues(); 312 final Uri uri; 313 314 if (mailbox.mType == Mailbox.TYPE_INBOX) { 315 cv.put(AccountColumns.SYNC_INTERVAL, account.mSyncInterval); 316 cv.put(AccountColumns.SYNC_LOOKBACK, account.mSyncLookback); 317 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account.mId); 318 } else { 319 cv.put(MailboxColumns.SYNC_INTERVAL, mailbox.mSyncInterval); 320 cv.put(MailboxColumns.SYNC_LOOKBACK, mailbox.mSyncLookback); 321 uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailbox.mId); 322 } 323 context.getContentResolver().update(uri, cv, null, null); 324 325 Log.i(Logging.LOG_TAG, "Saved: " + uri); 326 return null; 327 } 328 329 @Override 330 protected void onSuccess(Void result) { 331 // must be called on the ui thread 332 RefreshManager.getInstance(context).refreshMessageList(account.mId, mailbox.mId, 333 true); 334 } 335 }.executeSerial((Void [])null); 336 } 337 338 @Override 339 public boolean onOptionsItemSelected(MenuItem item) { 340 if (item.getItemId() == android.R.id.home) { 341 onBackPressed(); 342 return true; 343 } 344 return super.onOptionsItemSelected(item); 345 } 346} 347