Email.java revision 5b81690de1ea15035ab0539df683acd8e28b0ebd
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.MessageCompose; 21import com.android.email.provider.EmailContent; 22import com.android.email.service.AttachmentDownloadService; 23import com.android.email.service.MailService; 24import com.android.exchange.Eas; 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 * If true, enable the UI thread check when accessing the filesystem. 74 */ 75 public static final boolean DEBUG_THREAD_CHECK = false; // DON'T SUBMIT WITH TRUE 76 77 /** 78 * If true, inhibit hardware graphics acceleration in UI (for a/b testing) 79 */ 80 public static boolean sDebugInhibitGraphicsAcceleration = false; 81 82 /** 83 * The MIME type(s) of attachments we're willing to send via attachments. 84 * 85 * Any attachments may be added via Intents with Intent.ACTION_SEND or ACTION_SEND_MULTIPLE. 86 */ 87 public static final String[] ACCEPTABLE_ATTACHMENT_SEND_INTENT_TYPES = new String[] { 88 "*/*", 89 }; 90 91 /** 92 * The MIME type(s) of attachments we're willing to send from the internal UI. 93 * 94 * NOTE: At the moment it is not possible to open a chooser with a list of filter types, so 95 * the chooser is only opened with the first item in the list. 96 */ 97 public static final String[] ACCEPTABLE_ATTACHMENT_SEND_UI_TYPES = new String[] { 98 "image/*", 99 "video/*", 100 }; 101 102 /** 103 * The MIME type(s) of attachments we're willing to view. 104 */ 105 public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { 106 "*/*", 107 }; 108 109 /** 110 * The MIME type(s) of attachments we're not willing to view. 111 */ 112 public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] { 113 }; 114 115 /** 116 * The MIME type(s) of attachments we're willing to download to SD. 117 */ 118 public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] { 119 "image/*", 120 }; 121 122 /** 123 * The MIME type(s) of attachments we're not willing to download to SD. 124 */ 125 public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] { 126 }; 127 128 /** 129 * Specifies how many messages will be shown in a folder by default. This number is set 130 * on each new folder and can be incremented with "Load more messages..." by the 131 * VISIBLE_LIMIT_INCREMENT 132 */ 133 public static final int VISIBLE_LIMIT_DEFAULT = 25; 134 135 /** 136 * Number of additional messages to load when a user selects "Load more messages..." 137 */ 138 public static final int VISIBLE_LIMIT_INCREMENT = 25; 139 140 /** 141 * The maximum size of an attachment we're willing to download (either View or Save) 142 * Attachments that are base64 encoded (most) will be about 1.375x their actual size 143 * so we should probably factor that in. A 5MB attachment will generally be around 144 * 6.8MB downloaded but only 5MB saved. 145 */ 146 public static final int MAX_ATTACHMENT_DOWNLOAD_SIZE = (5 * 1024 * 1024); 147 148 /** 149 * The maximum size of an attachment we're willing to upload (measured as stored on disk). 150 * Attachments that are base64 encoded (most) will be about 1.375x their actual size 151 * so we should probably factor that in. A 5MB attachment will generally be around 152 * 6.8MB uploaded. 153 */ 154 public static final int MAX_ATTACHMENT_UPLOAD_SIZE = (5 * 1024 * 1024); 155 156 /** 157 * This is used to force stacked UI to return to the "welcome" screen any time we change 158 * the accounts list (e.g. deleting accounts in the Account Manager preferences.) 159 */ 160 private static boolean sAccountsChangedNotification = false; 161 162 public static final String EXCHANGE_ACCOUNT_MANAGER_TYPE = "com.android.exchange"; 163 public static final String POP_IMAP_ACCOUNT_MANAGER_TYPE = "com.android.email"; 164 165 private static File sTempDirectory; 166 167 private static Thread sUiThread; 168 169 public static void setTempDirectory(Context context) { 170 sTempDirectory = context.getCacheDir(); 171 } 172 173 public static File getTempDirectory() { 174 if (sTempDirectory == null) { 175 throw new RuntimeException( 176 "TempDirectory not set. " + 177 "If in a unit test, call Email.setTempDirectory(context) in setUp()."); 178 } 179 return sTempDirectory; 180 } 181 182 /** 183 * Called throughout the application when the number of accounts has changed. This method 184 * enables or disables the Compose activity, the boot receiver and the service based on 185 * whether any accounts are configured. Returns true if there are any accounts configured. 186 */ 187 public static boolean setServicesEnabled(Context context) { 188 Cursor c = null; 189 try { 190 c = context.getContentResolver().query( 191 EmailContent.Account.CONTENT_URI, 192 EmailContent.Account.ID_PROJECTION, 193 null, null, null); 194 boolean enable = c.getCount() > 0; 195 setServicesEnabled(context, enable); 196 return enable; 197 } finally { 198 if (c != null) { 199 c.close(); 200 } 201 } 202 } 203 204 public static void setServicesEnabled(Context context, boolean enabled) { 205 PackageManager pm = context.getPackageManager(); 206 if (!enabled && pm.getComponentEnabledSetting( 207 new ComponentName(context, MailService.class)) == 208 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 209 /* 210 * If no accounts now exist but the service is still enabled we're about to disable it 211 * so we'll reschedule to kill off any existing alarms. 212 */ 213 MailService.actionReschedule(context); 214 } 215 pm.setComponentEnabledSetting( 216 new ComponentName(context, MessageCompose.class), 217 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 218 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 219 PackageManager.DONT_KILL_APP); 220 pm.setComponentEnabledSetting( 221 new ComponentName(context, AccountShortcutPicker.class), 222 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 223 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 224 PackageManager.DONT_KILL_APP); 225 pm.setComponentEnabledSetting( 226 new ComponentName(context, MailService.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, AttachmentDownloadService.class), 232 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 233 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 234 PackageManager.DONT_KILL_APP); 235 if (enabled && pm.getComponentEnabledSetting( 236 new ComponentName(context, MailService.class)) == 237 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 238 /* 239 * And now if accounts do exist then we've just enabled the service and we want to 240 * schedule alarms for the new accounts. 241 */ 242 MailService.actionReschedule(context); 243 } 244 // Start/stop the AttachmentDownloadService, depending on whether there are any accounts 245 Intent intent = new Intent(context, AttachmentDownloadService.class); 246 if (enabled) { 247 context.startService(intent); 248 } else { 249 context.stopService(intent); 250 } 251 } 252 253 @Override 254 public void onCreate() { 255 super.onCreate(); 256 sUiThread = Thread.currentThread(); 257 Preferences prefs = Preferences.getPreferences(this); 258 DEBUG = prefs.getEnableDebugLogging(); 259 sDebugInhibitGraphicsAcceleration = prefs.getInhibitGraphicsAcceleration(); 260 setTempDirectory(this); 261 262 // Tie MailRefreshManager to the Controller. 263 RefreshManager.getInstance(this); 264 // Reset all accounts to default visible window 265 Controller.getInstance(this).resetVisibleLimits(); 266 267 // Enable logging in the EAS service, so it starts up as early as possible. 268 updateLoggingFlags(this); 269 } 270 271 /** 272 * Load enabled debug flags from the preferences and update the EAS debug flag. 273 */ 274 public static void updateLoggingFlags(Context context) { 275 //EXCHANGE-REMOVE-SECTION-START 276 Preferences prefs = Preferences.getPreferences(context); 277 int debugLogging = prefs.getEnableDebugLogging() ? Eas.DEBUG_BIT : 0; 278 int exchangeLogging = prefs.getEnableExchangeLogging() ? Eas.DEBUG_EXCHANGE_BIT : 0; 279 int fileLogging = prefs.getEnableExchangeFileLogging() ? Eas.DEBUG_FILE_BIT : 0; 280 int debugBits = debugLogging | exchangeLogging | fileLogging; 281 Controller.getInstance(context).serviceLogging(debugBits); 282 //EXCHANGE-REMOVE-SECTION-END 283 } 284 285 /** 286 * Internal, utility method for logging. 287 * The calls to log() must be guarded with "if (Email.LOGD)" for performance reasons. 288 */ 289 public static void log(String message) { 290 Log.d(LOG_TAG, message); 291 } 292 293 /** 294 * Called by the accounts reconciler to notify that accounts have changed, or by "Welcome" 295 * to clear the flag. 296 * @param setFlag true to set the notification flag, false to clear it 297 */ 298 public static synchronized void setNotifyUiAccountsChanged(boolean setFlag) { 299 sAccountsChangedNotification = setFlag; 300 } 301 302 /** 303 * Called from activity onResume() functions to check for an accounts-changed condition, at 304 * which point they should finish() and jump to the Welcome activity. 305 */ 306 public static synchronized boolean getNotifyUiAccountsChanged() { 307 return sAccountsChangedNotification; 308 } 309 310 public static void warnIfUiThread() { 311 if (Thread.currentThread().equals(sUiThread)) { 312 Log.w(Email.LOG_TAG, "Method called on the UI thread", new Exception("STACK TRACE")); 313 } 314 } 315} 316