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