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