Email.java revision 0a8030562a5235591a5f5364bf5e6855ffa62861
1/* 2 * Copyright (C) 2008 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; 18 19import com.android.email.activity.AccountShortcutPicker; 20import com.android.email.activity.Debug; 21import com.android.email.activity.MessageCompose; 22import com.android.email.provider.EmailContent; 23import com.android.email.service.BootReceiver; 24import com.android.email.service.MailService; 25 26import android.app.Application; 27import android.content.ComponentName; 28import android.content.Context; 29import android.content.pm.PackageManager; 30import android.database.Cursor; 31import android.text.format.DateUtils; 32import android.util.Log; 33 34import java.io.File; 35import java.util.HashMap; 36 37public class Email extends Application { 38 public static final String LOG_TAG = "Email"; 39 40 /** 41 * If this is enabled there will be additional logging information sent to 42 * Log.d, including protocol dumps. 43 * 44 * This should only be used for logs that are useful for debbuging user problems, 45 * not for internal/development logs. 46 * 47 * This can be enabled by typing "debug" in the AccountFolderList activity. 48 * Changing the value to 'true' here will likely have no effect at all! 49 * 50 * TODO: rename this to sUserDebug, and rename LOGD below to DEBUG. 51 */ 52 public static boolean DEBUG = false; 53 54 /** 55 * If this is enabled than logging that normally hides sensitive information 56 * like passwords will show that information. 57 */ 58 public static boolean DEBUG_SENSITIVE = false; 59 60 /** 61 * Set this to 'true' to enable as much Email logging as possible. 62 * Do not check-in with it set to 'true'! 63 */ 64 public static final boolean LOGD = false; 65 66 /** 67 * The MIME type(s) of attachments we're willing to send via attachments. 68 * 69 * Any attachments may be added via Intents with Intent.ACTION_SEND or ACTION_SEND_MULTIPLE. 70 */ 71 public static final String[] ACCEPTABLE_ATTACHMENT_SEND_INTENT_TYPES = new String[] { 72 "*/*", 73 }; 74 75 /** 76 * The MIME type(s) of attachments we're willing to send from the internal UI. 77 * 78 * NOTE: At the moment it is not possible to open a chooser with a list of filter types, so 79 * the chooser is only opened with the first item in the list. 80 */ 81 public static final String[] ACCEPTABLE_ATTACHMENT_SEND_UI_TYPES = new String[] { 82 "image/*", 83 "video/*", 84 }; 85 86 /** 87 * The MIME type(s) of attachments we're willing to view. 88 */ 89 public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { 90 "*/*", 91 }; 92 93 /** 94 * The MIME type(s) of attachments we're not willing to view. 95 */ 96 public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { 97 }; 98 99 /** 100 * The MIME type(s) of attachments we're willing to download to SD. 101 */ 102 public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] { 103 "image/*", 104 }; 105 106 /** 107 * The MIME type(s) of attachments we're not willing to download to SD. 108 */ 109 public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] { 110 }; 111 112 /** 113 * Specifies how many messages will be shown in a folder by default. This number is set 114 * on each new folder and can be incremented with "Load more messages..." by the 115 * VISIBLE_LIMIT_INCREMENT 116 */ 117 public static final int VISIBLE_LIMIT_DEFAULT = 25; 118 119 /** 120 * Number of additional messages to load when a user selects "Load more messages..." 121 */ 122 public static final int VISIBLE_LIMIT_INCREMENT = 25; 123 124 /** 125 * The maximum size of an attachment we're willing to download (either View or Save) 126 * Attachments that are base64 encoded (most) will be about 1.375x their actual size 127 * so we should probably factor that in. A 5MB attachment will generally be around 128 * 6.8MB downloaded but only 5MB saved. 129 */ 130 public static final int MAX_ATTACHMENT_DOWNLOAD_SIZE = (5 * 1024 * 1024); 131 132 /** 133 * The maximum size of an attachment we're willing to upload (measured as stored on disk). 134 * Attachments that are base64 encoded (most) will be about 1.375x their actual size 135 * so we should probably factor that in. A 5MB attachment will generally be around 136 * 6.8MB uploaded. 137 */ 138 public static final int MAX_ATTACHMENT_UPLOAD_SIZE = (5 * 1024 * 1024); 139 140 private static HashMap<Long, Long> sMailboxSyncTimes = new HashMap<Long, Long>(); 141 private static final long UPDATE_INTERVAL = 5 * DateUtils.MINUTE_IN_MILLIS; 142 143 /** 144 * This is used to force stacked UI to return to the "welcome" screen any time we change 145 * the accounts list (e.g. deleting accounts in the Account Manager preferences.) 146 */ 147 private static boolean sAccountsChangedNotification = false; 148 149 public static final String EXCHANGE_ACCOUNT_MANAGER_TYPE = "com.android.exchange"; 150 151 // The color chip resources and the RGB color values in the array below must be kept in sync 152 private static final int[] ACCOUNT_COLOR_CHIP_RES_IDS = new int[] { 153 R.drawable.appointment_indicator_leftside_1, 154 R.drawable.appointment_indicator_leftside_2, 155 R.drawable.appointment_indicator_leftside_3, 156 R.drawable.appointment_indicator_leftside_4, 157 R.drawable.appointment_indicator_leftside_5, 158 R.drawable.appointment_indicator_leftside_6, 159 R.drawable.appointment_indicator_leftside_7, 160 R.drawable.appointment_indicator_leftside_8, 161 R.drawable.appointment_indicator_leftside_9, 162 }; 163 164 private static final int[] ACCOUNT_COLOR_CHIP_RGBS = new int[] { 165 0x71aea7, 166 0x621919, 167 0x18462f, 168 0xbf8e52, 169 0x001f79, 170 0xa8afc2, 171 0x6b64c4, 172 0x738359, 173 0x9d50a4, 174 }; 175 176 private static File sTempDirectory; 177 178 /* package for testing */ static int getColorIndexFromAccountId(long accountId) { 179 // Account id is 1-based, so - 1. 180 // Use abs so that it won't possibly return negative. 181 return Math.abs((int) (accountId - 1) % ACCOUNT_COLOR_CHIP_RES_IDS.length); 182 } 183 184 public static int getAccountColorResourceId(long accountId) { 185 return ACCOUNT_COLOR_CHIP_RES_IDS[getColorIndexFromAccountId(accountId)]; 186 } 187 188 public static int getAccountColor(long accountId) { 189 return ACCOUNT_COLOR_CHIP_RGBS[getColorIndexFromAccountId(accountId)]; 190 } 191 192 public static void setTempDirectory(Context context) { 193 sTempDirectory = context.getCacheDir(); 194 } 195 196 public static File getTempDirectory() { 197 if (sTempDirectory == null) { 198 throw new RuntimeException( 199 "TempDirectory not set. " + 200 "If in a unit test, call Email.setTempDirectory(context) in setUp()."); 201 } 202 return sTempDirectory; 203 } 204 205 /** 206 * Called throughout the application when the number of accounts has changed. This method 207 * enables or disables the Compose activity, the boot receiver and the service based on 208 * whether any accounts are configured. Returns true if there are any accounts configured. 209 */ 210 public static boolean setServicesEnabled(Context context) { 211 Cursor c = null; 212 try { 213 c = context.getContentResolver().query( 214 EmailContent.Account.CONTENT_URI, 215 EmailContent.Account.ID_PROJECTION, 216 null, null, null); 217 boolean enable = c.getCount() > 0; 218 setServicesEnabled(context, enable); 219 return enable; 220 } finally { 221 if (c != null) { 222 c.close(); 223 } 224 } 225 } 226 227 public static void setServicesEnabled(Context context, boolean enabled) { 228 PackageManager pm = context.getPackageManager(); 229 if (!enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) == 230 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 231 /* 232 * If no accounts now exist but the service is still enabled we're about to disable it 233 * so we'll reschedule to kill off any existing alarms. 234 */ 235 MailService.actionReschedule(context); 236 } 237 pm.setComponentEnabledSetting( 238 new ComponentName(context, MessageCompose.class), 239 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 240 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 241 PackageManager.DONT_KILL_APP); 242 pm.setComponentEnabledSetting( 243 new ComponentName(context, AccountShortcutPicker.class), 244 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 245 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 246 PackageManager.DONT_KILL_APP); 247 pm.setComponentEnabledSetting( 248 new ComponentName(context, BootReceiver.class), 249 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 250 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 251 PackageManager.DONT_KILL_APP); 252 pm.setComponentEnabledSetting( 253 new ComponentName(context, MailService.class), 254 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 255 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 256 PackageManager.DONT_KILL_APP); 257 if (enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) == 258 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 259 /* 260 * And now if accounts do exist then we've just enabled the service and we want to 261 * schedule alarms for the new accounts. 262 */ 263 MailService.actionReschedule(context); 264 } 265 } 266 267 @Override 268 public void onCreate() { 269 super.onCreate(); 270 Preferences prefs = Preferences.getPreferences(this); 271 DEBUG = prefs.getEnableDebugLogging(); 272 DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging(); 273 setTempDirectory(this); 274 275 // Reset all accounts to default visible window 276 Controller.getInstance(this).resetVisibleLimits(); 277 278 // Enable logging in the EAS service, so it starts up as early as possible. 279 Debug.updateLoggingFlags(this); 280 } 281 282 /** 283 * Internal, utility method for logging. 284 * The calls to log() must be guarded with "if (Email.LOGD)" for performance reasons. 285 */ 286 public static void log(String message) { 287 Log.d(LOG_TAG, message); 288 } 289 290 /** 291 * Update the time when the mailbox is refreshed 292 * @param mailboxId mailbox which need to be updated 293 */ 294 public static void updateMailboxRefreshTime(long mailboxId) { 295 synchronized (sMailboxSyncTimes) { 296 sMailboxSyncTimes.put(mailboxId, System.currentTimeMillis()); 297 } 298 } 299 300 /** 301 * Check if the mailbox is need to be refreshed 302 * @param mailboxId mailbox checked the need of refreshing 303 * @return the need of refreshing 304 */ 305 public static boolean mailboxRequiresRefresh(long mailboxId) { 306 synchronized (sMailboxSyncTimes) { 307 return 308 !sMailboxSyncTimes.containsKey(mailboxId) 309 || (System.currentTimeMillis() - sMailboxSyncTimes.get(mailboxId) 310 > UPDATE_INTERVAL); 311 } 312 } 313 314 /** 315 * Called by the accounts reconciler to notify that accounts have changed, or by "Welcome" 316 * to clear the flag. 317 * @param setFlag true to set the notification flag, false to clear it 318 */ 319 public static synchronized void setNotifyUiAccountsChanged(boolean setFlag) { 320 sAccountsChangedNotification = setFlag; 321 } 322 323 /** 324 * Called from activity onResume() functions to check for an accounts-changed condition, at 325 * which point they should finish() and jump to the Welcome activity. 326 */ 327 public static synchronized boolean getNotifyUiAccountsChanged() { 328 return sAccountsChangedNotification; 329 } 330} 331