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