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