MailActivityEmail.java revision 281c6365fb95037ca284dd8c910538639e8b3dcb
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.email2.ui; 18 19import android.content.ComponentName; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.pm.PackageManager; 24import android.content.UriMatcher; 25import android.database.Cursor; 26import android.net.Uri; 27import android.os.Bundle; 28 29import com.android.email.NotificationController; 30import com.android.email.Preferences; 31import com.android.email.R; 32import com.android.email.provider.EmailProvider; 33import com.android.email.service.AttachmentDownloadService; 34import com.android.email.service.EmailServiceUtils; 35import com.android.email.service.MailService; 36import com.android.emailcommon.Logging; 37import com.android.emailcommon.TempDirectory; 38import com.android.emailcommon.provider.Account; 39import com.android.emailcommon.provider.EmailContent; 40import com.android.emailcommon.provider.Mailbox; 41import com.android.emailcommon.service.EmailServiceProxy; 42import com.android.emailcommon.utility.EmailAsyncTask; 43import com.android.emailcommon.utility.IntentUtilities; 44import com.android.emailcommon.utility.Utility; 45import com.android.mail.providers.Folder; 46import com.android.mail.providers.UIProvider; 47import com.android.mail.utils.LogTag; 48import com.android.mail.utils.LogUtils; 49import com.android.mail.utils.Utils; 50 51public class MailActivityEmail extends com.android.mail.ui.MailActivity { 52 /** 53 * If this is enabled there will be additional logging information sent to 54 * LogUtils.d, including protocol dumps. 55 * 56 * This should only be used for logs that are useful for debbuging user problems, 57 * not for internal/development logs. 58 * 59 * This can be enabled by typing "debug" in the AccountFolderList activity. 60 * Changing the value to 'true' here will likely have no effect at all! 61 * 62 * TODO: rename this to sUserDebug, and rename LOGD below to DEBUG. 63 */ 64 public static boolean DEBUG; 65 66 public static final String LOG_TAG = LogTag.getLogTag(); 67 68 // Exchange debugging flags (passed to Exchange, when available, via EmailServiceProxy) 69 public static boolean DEBUG_EXCHANGE; 70 public static boolean DEBUG_VERBOSE; 71 public static boolean DEBUG_FILE; 72 73 /** 74 * If true, inhibit hardware graphics acceleration in UI (for a/b testing) 75 */ 76 public static boolean sDebugInhibitGraphicsAcceleration = false; 77 78 /** 79 * This is used to force stacked UI to return to the "welcome" screen any time we change 80 * the accounts list (e.g. deleting accounts in the Account Manager preferences.) 81 */ 82 private static boolean sAccountsChangedNotification = false; 83 84 private static String sMessageDecodeErrorString; 85 86 private static Thread sUiThread; 87 88 private static final int MATCH_LEGACY_SHORTCUT_INTENT = 1; 89 /** 90 * A matcher for data URI's that specify conversation list info. 91 */ 92 private static final UriMatcher sUrlMatcher = new UriMatcher(UriMatcher.NO_MATCH); 93 static { 94 sUrlMatcher.addURI( 95 EmailProvider.LEGACY_AUTHORITY, "view/mailbox", MATCH_LEGACY_SHORTCUT_INTENT); 96 } 97 98 99 /** 100 * Asynchronous version of {@link #setServicesEnabledSync(Context)}. Use when calling from 101 * UI thread (or lifecycle entry points.) 102 * 103 * @param context 104 */ 105 public static void setServicesEnabledAsync(final Context context) { 106 EmailAsyncTask.runAsyncParallel(new Runnable() { 107 @Override 108 public void run() { 109 setServicesEnabledSync(context); 110 } 111 }); 112 } 113 114 /** 115 * Called throughout the application when the number of accounts has changed. This method 116 * enables or disables the Compose activity, the boot receiver and the service based on 117 * whether any accounts are configured. 118 * 119 * Blocking call - do not call from UI/lifecycle threads. 120 * 121 * @param context 122 * @return true if there are any accounts configured. 123 */ 124 public static boolean setServicesEnabledSync(Context context) { 125 // Make sure we're initialized 126 EmailContent.init(context); 127 Cursor c = null; 128 try { 129 c = context.getContentResolver().query( 130 Account.CONTENT_URI, 131 Account.ID_PROJECTION, 132 null, null, null); 133 boolean enable = c.getCount() > 0; 134 setServicesEnabled(context, enable); 135 return enable; 136 } finally { 137 if (c != null) { 138 c.close(); 139 } 140 } 141 } 142 143 private static void setServicesEnabled(Context context, boolean enabled) { 144 PackageManager pm = context.getPackageManager(); 145 pm.setComponentEnabledSetting( 146 new ComponentName(context, MailService.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, AttachmentDownloadService.class), 152 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 153 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 154 PackageManager.DONT_KILL_APP); 155 156 // Start/stop the various services depending on whether there are any accounts 157 startOrStopService(enabled, context, new Intent(context, AttachmentDownloadService.class)); 158 NotificationController.getInstance(context).watchForMessages(); 159 } 160 161 /** 162 * Starts or stops the service as necessary. 163 * @param enabled If {@code true}, the service will be started. Otherwise, it will be stopped. 164 * @param context The context to manage the service with. 165 * @param intent The intent of the service to be managed. 166 */ 167 private static void startOrStopService(boolean enabled, Context context, Intent intent) { 168 if (enabled) { 169 context.startService(intent); 170 } else { 171 context.stopService(intent); 172 } 173 } 174 175 @Override 176 public void onCreate(Bundle bundle) { 177 final Intent intent = getIntent(); 178 final Uri data = intent != null ? intent.getData() : null; 179 if (data != null) { 180 final int match = sUrlMatcher.match(data); 181 switch (match) { 182 case MATCH_LEGACY_SHORTCUT_INTENT: { 183 final long mailboxId = IntentUtilities.getMailboxIdFromIntent(intent); 184 final Mailbox mailbox = Mailbox.restoreMailboxWithId(this, mailboxId); 185 if (mailbox == null) { 186 LogUtils.e(LOG_TAG, "unable to restore mailbox"); 187 break; 188 } 189 190 final Intent viewIntent = getViewIntent(mailbox.mAccountKey, mailboxId); 191 if (viewIntent != null) { 192 setIntent(viewIntent); 193 } 194 break; 195 } 196 } 197 } 198 199 super.onCreate(bundle); 200 sUiThread = Thread.currentThread(); 201 Preferences prefs = Preferences.getPreferences(this); 202 DEBUG = prefs.getEnableDebugLogging(); 203 sDebugInhibitGraphicsAcceleration = prefs.getInhibitGraphicsAcceleration(); 204 enableStrictMode(prefs.getEnableStrictMode()); 205 TempDirectory.setTempDirectory(this); 206 207 // Enable logging in the EAS service, so it starts up as early as possible. 208 updateLoggingFlags(this); 209 210 // Get a helper string used deep inside message decoders (which don't have context) 211 sMessageDecodeErrorString = getString(R.string.message_decode_error); 212 213 // Make sure all required services are running when the app is started (can prevent 214 // issues after an adb sync/install) 215 setServicesEnabledAsync(this); 216 } 217 218 /** 219 * Load enabled debug flags from the preferences and update the EAS debug flag. 220 */ 221 public static void updateLoggingFlags(Context context) { 222 Preferences prefs = Preferences.getPreferences(context); 223 int debugLogging = prefs.getEnableDebugLogging() ? EmailServiceProxy.DEBUG_BIT : 0; 224 int verboseLogging = 225 prefs.getEnableExchangeLogging() ? EmailServiceProxy.DEBUG_VERBOSE_BIT : 0; 226 int fileLogging = 227 prefs.getEnableExchangeFileLogging() ? EmailServiceProxy.DEBUG_FILE_BIT : 0; 228 int enableStrictMode = 229 prefs.getEnableStrictMode() ? EmailServiceProxy.DEBUG_ENABLE_STRICT_MODE : 0; 230 int debugBits = debugLogging | verboseLogging | fileLogging | enableStrictMode; 231 EmailServiceUtils.setRemoteServicesLogging(context, debugBits); 232 } 233 234 /** 235 * Internal, utility method for logging. 236 * The calls to log() must be guarded with "if (Email.LOGD)" for performance reasons. 237 */ 238 public static void log(String message) { 239 LogUtils.d(Logging.LOG_TAG, message); 240 } 241 242 /** 243 * Called by the accounts reconciler to notify that accounts have changed, or by "Welcome" 244 * to clear the flag. 245 * @param setFlag true to set the notification flag, false to clear it 246 */ 247 public static synchronized void setNotifyUiAccountsChanged(boolean setFlag) { 248 sAccountsChangedNotification = setFlag; 249 } 250 251 /** 252 * Called from activity onResume() functions to check for an accounts-changed condition, at 253 * which point they should finish() and jump to the Welcome activity. 254 */ 255 public static synchronized boolean getNotifyUiAccountsChanged() { 256 return sAccountsChangedNotification; 257 } 258 259 public static void warnIfUiThread() { 260 if (Thread.currentThread().equals(sUiThread)) { 261 LogUtils.w(Logging.LOG_TAG, "Method called on the UI thread", 262 new Exception("STACK TRACE")); 263 } 264 } 265 266 /** 267 * Retrieve a simple string that can be used when message decoders encounter bad data. 268 * This is provided here because the protocol decoders typically don't have mContext. 269 */ 270 public static String getMessageDecodeErrorString() { 271 return sMessageDecodeErrorString != null ? sMessageDecodeErrorString : ""; 272 } 273 274 public static void enableStrictMode(boolean enabled) { 275 Utility.enableStrictMode(enabled); 276 } 277 278 private Intent getViewIntent(long accountId, long mailboxId) { 279 final ContentResolver contentResolver = getContentResolver(); 280 281 final Cursor accountCursor = contentResolver.query( 282 EmailProvider.uiUri("uiaccount", accountId), 283 UIProvider.ACCOUNTS_PROJECTION_NO_CAPABILITIES, 284 null, null, null); 285 286 if (accountCursor == null) { 287 LogUtils.e(LOG_TAG, "Null account cursor for mAccountId %d", accountId); 288 return null; 289 } 290 291 com.android.mail.providers.Account account = null; 292 try { 293 if (accountCursor.moveToFirst()) { 294 account = new com.android.mail.providers.Account(accountCursor); 295 } 296 } finally { 297 accountCursor.close(); 298 } 299 300 301 final Cursor folderCursor = contentResolver.query( 302 EmailProvider.uiUri("uifolder", mailboxId), 303 UIProvider.FOLDERS_PROJECTION, null, null, null); 304 305 if (folderCursor == null) { 306 LogUtils.e(LOG_TAG, "Null folder cursor for account %d, mailbox %d", 307 accountId, mailboxId); 308 return null; 309 } 310 311 Folder folder = null; 312 try { 313 if (folderCursor.moveToFirst()) { 314 folder = new Folder(folderCursor); 315 } else { 316 LogUtils.e(LOG_TAG, "Empty folder cursor for account %d, mailbox %d", 317 accountId, mailboxId); 318 return null; 319 } 320 } finally { 321 folderCursor.close(); 322 } 323 324 return Utils.createViewFolderIntent(this, folder.folderUri.fullUri, account); 325 } 326} 327