Email.java revision f5418f1f93b02e7fab9f15eb201800b65510998e
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.ShortcutPicker; 20import com.android.email.activity.MessageCompose; 21import com.android.email.service.AttachmentDownloadService; 22import com.android.email.service.MailService; 23import com.android.email.service.NotificationService; 24import com.android.email.widget.WidgetConfiguration; 25import com.android.emailcommon.Logging; 26import com.android.emailcommon.TempDirectory; 27import com.android.emailcommon.provider.Account; 28import com.android.emailcommon.service.EmailServiceProxy; 29import com.android.emailcommon.utility.EmailAsyncTask; 30import com.android.emailcommon.utility.Utility; 31 32import android.app.Application; 33import android.content.ComponentName; 34import android.content.Context; 35import android.content.Intent; 36import android.content.pm.PackageManager; 37import android.database.Cursor; 38import android.util.Log; 39 40public class Email extends Application { 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; 54 55 // Exchange debugging flags (passed to Exchange, when available, via EmailServiceProxy) 56 public static boolean DEBUG_EXCHANGE; 57 public static boolean DEBUG_EXCHANGE_VERBOSE; 58 public static boolean DEBUG_EXCHANGE_FILE; 59 60 /** 61 * If true, inhibit hardware graphics acceleration in UI (for a/b testing) 62 */ 63 public static boolean sDebugInhibitGraphicsAcceleration = false; 64 65 /** 66 * Specifies how many messages will be shown in a folder by default. This number is set 67 * on each new folder and can be incremented with "Load more messages..." by the 68 * VISIBLE_LIMIT_INCREMENT 69 */ 70 public static final int VISIBLE_LIMIT_DEFAULT = 25; 71 72 /** 73 * Number of additional messages to load when a user selects "Load more messages..." 74 */ 75 public static final int VISIBLE_LIMIT_INCREMENT = 25; 76 77 /** 78 * This is used to force stacked UI to return to the "welcome" screen any time we change 79 * the accounts list (e.g. deleting accounts in the Account Manager preferences.) 80 */ 81 private static boolean sAccountsChangedNotification = false; 82 83 private static String sMessageDecodeErrorString; 84 85 private static Thread sUiThread; 86 87 /** 88 * Asynchronous version of {@link #setServicesEnabledSync(Context)}. Use when calling from 89 * UI thread (or lifecycle entry points.) 90 * 91 * @param context 92 */ 93 public static void setServicesEnabledAsync(final Context context) { 94 EmailAsyncTask.runAsyncParallel(new Runnable() { 95 @Override 96 public void run() { 97 setServicesEnabledSync(context); 98 } 99 }); 100 } 101 102 /** 103 * Called throughout the application when the number of accounts has changed. This method 104 * enables or disables the Compose activity, the boot receiver and the service based on 105 * whether any accounts are configured. 106 * 107 * Blocking call - do not call from UI/lifecycle threads. 108 * 109 * @param context 110 * @return true if there are any accounts configured. 111 */ 112 public static boolean setServicesEnabledSync(Context context) { 113 Cursor c = null; 114 try { 115 c = context.getContentResolver().query( 116 Account.CONTENT_URI, 117 Account.ID_PROJECTION, 118 null, null, null); 119 boolean enable = c.getCount() > 0; 120 setServicesEnabled(context, enable); 121 return enable; 122 } finally { 123 if (c != null) { 124 c.close(); 125 } 126 } 127 } 128 129 private static void setServicesEnabled(Context context, boolean enabled) { 130 PackageManager pm = context.getPackageManager(); 131 if (!enabled && pm.getComponentEnabledSetting( 132 new ComponentName(context, MailService.class)) == 133 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 134 /* 135 * If no accounts now exist but the service is still enabled we're about to disable it 136 * so we'll reschedule to kill off any existing alarms. 137 */ 138 MailService.actionReschedule(context); 139 } 140 pm.setComponentEnabledSetting( 141 new ComponentName(context, MessageCompose.class), 142 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 143 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 144 PackageManager.DONT_KILL_APP); 145 pm.setComponentEnabledSetting( 146 new ComponentName(context, ShortcutPicker.class), 147 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 148 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 149 PackageManager.DONT_KILL_APP); 150 pm.setComponentEnabledSetting( 151 new ComponentName(context, WidgetConfiguration.class), 152 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 153 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 154 PackageManager.DONT_KILL_APP); 155 pm.setComponentEnabledSetting( 156 new ComponentName(context, MailService.class), 157 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 158 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 159 PackageManager.DONT_KILL_APP); 160 pm.setComponentEnabledSetting( 161 new ComponentName(context, AttachmentDownloadService.class), 162 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 163 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 164 PackageManager.DONT_KILL_APP); 165 pm.setComponentEnabledSetting( 166 new ComponentName(context, NotificationService.class), 167 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 168 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 169 PackageManager.DONT_KILL_APP); 170 if (enabled && pm.getComponentEnabledSetting( 171 new ComponentName(context, MailService.class)) == 172 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 173 /* 174 * And now if accounts do exist then we've just enabled the service and we want to 175 * schedule alarms for the new accounts. 176 */ 177 MailService.actionReschedule(context); 178 } 179 180 // Start/stop the various services depending on whether there are any accounts 181 startOrStopService(enabled, context, new Intent(context, AttachmentDownloadService.class)); 182 startOrStopService(enabled, context, new Intent(context, NotificationService.class)); 183 } 184 185 /** 186 * Starts or stops the service as necessary. 187 * @param enabled If {@code true}, the service will be started. Otherwise, it will be stopped. 188 * @param context The context to manage the service with. 189 * @param intent The intent of the service to be managed. 190 */ 191 private static void startOrStopService(boolean enabled, Context context, Intent intent) { 192 if (enabled) { 193 context.startService(intent); 194 } else { 195 context.stopService(intent); 196 } 197 } 198 199 @Override 200 public void onCreate() { 201 super.onCreate(); 202 sUiThread = Thread.currentThread(); 203 Preferences prefs = Preferences.getPreferences(this); 204 DEBUG = prefs.getEnableDebugLogging(); 205 sDebugInhibitGraphicsAcceleration = prefs.getInhibitGraphicsAcceleration(); 206 enableStrictMode(prefs.getEnableStrictMode()); 207 TempDirectory.setTempDirectory(this); 208 209 // Tie MailRefreshManager to the Controller. 210 RefreshManager.getInstance(this); 211 // Reset all accounts to default visible window 212 Controller.getInstance(this).resetVisibleLimits(); 213 214 // Enable logging in the EAS service, so it starts up as early as possible. 215 updateLoggingFlags(this); 216 217 // Get a helper string used deep inside message decoders (which don't have context) 218 sMessageDecodeErrorString = getString(R.string.message_decode_error); 219 220 // Make sure all required services are running when the app is started (can prevent 221 // issues after an adb sync/install) 222 setServicesEnabledAsync(this); 223 } 224 225 /** 226 * Load enabled debug flags from the preferences and update the EAS debug flag. 227 */ 228 public static void updateLoggingFlags(Context context) { 229 Preferences prefs = Preferences.getPreferences(context); 230 int debugLogging = prefs.getEnableDebugLogging() ? EmailServiceProxy.DEBUG_BIT : 0; 231 int verboseLogging = 232 prefs.getEnableExchangeLogging() ? EmailServiceProxy.DEBUG_VERBOSE_BIT : 0; 233 int fileLogging = 234 prefs.getEnableExchangeFileLogging() ? EmailServiceProxy.DEBUG_FILE_BIT : 0; 235 int enableStrictMode = 236 prefs.getEnableStrictMode() ? EmailServiceProxy.DEBUG_ENABLE_STRICT_MODE : 0; 237 int debugBits = debugLogging | verboseLogging | fileLogging | enableStrictMode; 238 Controller.getInstance(context).serviceLogging(debugBits); 239 } 240 241 /** 242 * Internal, utility method for logging. 243 * The calls to log() must be guarded with "if (Email.LOGD)" for performance reasons. 244 */ 245 public static void log(String message) { 246 Log.d(Logging.LOG_TAG, message); 247 } 248 249 /** 250 * Called by the accounts reconciler to notify that accounts have changed, or by "Welcome" 251 * to clear the flag. 252 * @param setFlag true to set the notification flag, false to clear it 253 */ 254 public static synchronized void setNotifyUiAccountsChanged(boolean setFlag) { 255 sAccountsChangedNotification = setFlag; 256 } 257 258 /** 259 * Called from activity onResume() functions to check for an accounts-changed condition, at 260 * which point they should finish() and jump to the Welcome activity. 261 */ 262 public static synchronized boolean getNotifyUiAccountsChanged() { 263 return sAccountsChangedNotification; 264 } 265 266 public static void warnIfUiThread() { 267 if (Thread.currentThread().equals(sUiThread)) { 268 Log.w(Logging.LOG_TAG, "Method called on the UI thread", new Exception("STACK TRACE")); 269 } 270 } 271 272 /** 273 * Retrieve a simple string that can be used when message decoders encounter bad data. 274 * This is provided here because the protocol decoders typically don't have mContext. 275 */ 276 public static String getMessageDecodeErrorString() { 277 return sMessageDecodeErrorString != null ? sMessageDecodeErrorString : ""; 278 } 279 280 public static void enableStrictMode(boolean enabled) { 281 Utility.enableStrictMode(enabled); 282 } 283} 284