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