• 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.email;
18 
19 import com.android.email.activity.AccountShortcutPicker;
20 import com.android.email.activity.Debug;
21 import com.android.email.activity.MessageCompose;
22 import com.android.email.provider.EmailContent;
23 import com.android.email.service.MailService;
24 
25 import android.app.Application;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.pm.PackageManager;
29 import android.database.Cursor;
30 import android.text.format.DateUtils;
31 import android.util.Log;
32 
33 import java.io.File;
34 import java.util.HashMap;
35 
36 public class Email extends Application {
37     public static final String LOG_TAG = "Email";
38 
39     /**
40      * If this is enabled there will be additional logging information sent to
41      * Log.d, including protocol dumps.
42      *
43      * This should only be used for logs that are useful for debbuging user problems,
44      * not for internal/development logs.
45      *
46      * This can be enabled by typing "debug" in the AccountFolderList activity.
47      * Changing the value to 'true' here will likely have no effect at all!
48      *
49      * TODO: rename this to sUserDebug, and rename LOGD below to DEBUG.
50      */
51     public static boolean DEBUG = false;
52 
53     /**
54      * If this is enabled than logging that normally hides sensitive information
55      * like passwords will show that information.
56      */
57     public static boolean DEBUG_SENSITIVE = false;
58 
59     /**
60      * Set this to 'true' to enable as much Email logging as possible.
61      * Do not check-in with it set to 'true'!
62      */
63     public static final boolean LOGD = false;
64 
65     /**
66      * The MIME type(s) of attachments we're willing to send via attachments.
67      *
68      * Any attachments may be added via Intents with Intent.ACTION_SEND or ACTION_SEND_MULTIPLE.
69      */
70     public static final String[] ACCEPTABLE_ATTACHMENT_SEND_INTENT_TYPES = new String[] {
71         "*/*",
72     };
73 
74     /**
75      * The MIME type(s) of attachments we're willing to send from the internal UI.
76      *
77      * NOTE:  At the moment it is not possible to open a chooser with a list of filter types, so
78      * the chooser is only opened with the first item in the list.
79      */
80     public static final String[] ACCEPTABLE_ATTACHMENT_SEND_UI_TYPES = new String[] {
81         "image/*",
82         "video/*",
83     };
84 
85     /**
86      * The MIME type(s) of attachments we're willing to view.
87      */
88     public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] {
89         "*/*",
90     };
91 
92     /**
93      * The MIME type(s) of attachments we're not willing to view.
94      */
95     public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] {
96     };
97 
98     /**
99      * The MIME type(s) of attachments we're willing to download to SD.
100      */
101     public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
102         "image/*",
103     };
104 
105     /**
106      * The MIME type(s) of attachments we're not willing to download to SD.
107      */
108     public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
109     };
110 
111     /**
112      * Specifies how many messages will be shown in a folder by default. This number is set
113      * on each new folder and can be incremented with "Load more messages..." by the
114      * VISIBLE_LIMIT_INCREMENT
115      */
116     public static final int VISIBLE_LIMIT_DEFAULT = 25;
117 
118     /**
119      * Number of additional messages to load when a user selects "Load more messages..."
120      */
121     public static final int VISIBLE_LIMIT_INCREMENT = 25;
122 
123     /**
124      * The maximum size of an attachment we're willing to download (either View or Save)
125      * Attachments that are base64 encoded (most) will be about 1.375x their actual size
126      * so we should probably factor that in. A 5MB attachment will generally be around
127      * 6.8MB downloaded but only 5MB saved.
128      */
129     public static final int MAX_ATTACHMENT_DOWNLOAD_SIZE = (5 * 1024 * 1024);
130 
131     /**
132      * The maximum size of an attachment we're willing to upload (measured as stored on disk).
133      * Attachments that are base64 encoded (most) will be about 1.375x their actual size
134      * so we should probably factor that in. A 5MB attachment will generally be around
135      * 6.8MB uploaded.
136      */
137     public static final int MAX_ATTACHMENT_UPLOAD_SIZE = (5 * 1024 * 1024);
138 
139     private static HashMap<Long, Long> sMailboxSyncTimes = new HashMap<Long, Long>();
140     private static final long UPDATE_INTERVAL = 5 * DateUtils.MINUTE_IN_MILLIS;
141 
142     /**
143      * This is used to force stacked UI to return to the "welcome" screen any time we change
144      * the accounts list (e.g. deleting accounts in the Account Manager preferences.)
145      */
146     private static boolean sAccountsChangedNotification = false;
147 
148     public static final String EXCHANGE_ACCOUNT_MANAGER_TYPE = "com.android.exchange";
149 
150     // The color chip resources and the RGB color values in the array below must be kept in sync
151     private static final int[] ACCOUNT_COLOR_CHIP_RES_IDS = new int[] {
152         R.drawable.appointment_indicator_leftside_1,
153         R.drawable.appointment_indicator_leftside_2,
154         R.drawable.appointment_indicator_leftside_3,
155         R.drawable.appointment_indicator_leftside_4,
156         R.drawable.appointment_indicator_leftside_5,
157         R.drawable.appointment_indicator_leftside_6,
158         R.drawable.appointment_indicator_leftside_7,
159         R.drawable.appointment_indicator_leftside_8,
160         R.drawable.appointment_indicator_leftside_9,
161     };
162 
163     private static final int[] ACCOUNT_COLOR_CHIP_RGBS = new int[] {
164         0x71aea7,
165         0x621919,
166         0x18462f,
167         0xbf8e52,
168         0x001f79,
169         0xa8afc2,
170         0x6b64c4,
171         0x738359,
172         0x9d50a4,
173     };
174 
175     private static File sTempDirectory;
176 
getColorIndexFromAccountId(long accountId)177     /* package for testing */ static int getColorIndexFromAccountId(long accountId) {
178         // Account id is 1-based, so - 1.
179         // Use abs so that it won't possibly return negative.
180         return Math.abs((int) (accountId - 1) % ACCOUNT_COLOR_CHIP_RES_IDS.length);
181     }
182 
getAccountColorResourceId(long accountId)183     public static int getAccountColorResourceId(long accountId) {
184         return ACCOUNT_COLOR_CHIP_RES_IDS[getColorIndexFromAccountId(accountId)];
185     }
186 
getAccountColor(long accountId)187     public static int getAccountColor(long accountId) {
188         return ACCOUNT_COLOR_CHIP_RGBS[getColorIndexFromAccountId(accountId)];
189     }
190 
setTempDirectory(Context context)191     public static void setTempDirectory(Context context) {
192         sTempDirectory = context.getCacheDir();
193     }
194 
getTempDirectory()195     public static File getTempDirectory() {
196         if (sTempDirectory == null) {
197             throw new RuntimeException(
198                     "TempDirectory not set.  " +
199                     "If in a unit test, call Email.setTempDirectory(context) in setUp().");
200         }
201         return sTempDirectory;
202     }
203 
204     /**
205      * Called throughout the application when the number of accounts has changed. This method
206      * enables or disables the Compose activity, the boot receiver and the service based on
207      * whether any accounts are configured.   Returns true if there are any accounts configured.
208      */
setServicesEnabled(Context context)209     public static boolean setServicesEnabled(Context context) {
210         Cursor c = null;
211         try {
212             c = context.getContentResolver().query(
213                     EmailContent.Account.CONTENT_URI,
214                     EmailContent.Account.ID_PROJECTION,
215                     null, null, null);
216             boolean enable = c.getCount() > 0;
217             setServicesEnabled(context, enable);
218             return enable;
219         } finally {
220             if (c != null) {
221                 c.close();
222             }
223         }
224     }
225 
setServicesEnabled(Context context, boolean enabled)226     public static void setServicesEnabled(Context context, boolean enabled) {
227         PackageManager pm = context.getPackageManager();
228         if (!enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
229                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
230             /*
231              * If no accounts now exist but the service is still enabled we're about to disable it
232              * so we'll reschedule to kill off any existing alarms.
233              */
234             MailService.actionReschedule(context);
235         }
236         pm.setComponentEnabledSetting(
237                 new ComponentName(context, MessageCompose.class),
238                 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
239                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
240                 PackageManager.DONT_KILL_APP);
241         pm.setComponentEnabledSetting(
242                 new ComponentName(context, AccountShortcutPicker.class),
243                 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
244                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
245                 PackageManager.DONT_KILL_APP);
246         pm.setComponentEnabledSetting(
247                 new ComponentName(context, MailService.class),
248                 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
249                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
250                 PackageManager.DONT_KILL_APP);
251         if (enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
252                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
253             /*
254              * And now if accounts do exist then we've just enabled the service and we want to
255              * schedule alarms for the new accounts.
256              */
257             MailService.actionReschedule(context);
258         }
259     }
260 
261     @Override
onCreate()262     public void onCreate() {
263         super.onCreate();
264         Preferences prefs = Preferences.getPreferences(this);
265         DEBUG = prefs.getEnableDebugLogging();
266         DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging();
267         setTempDirectory(this);
268 
269         // Reset all accounts to default visible window
270         Controller.getInstance(this).resetVisibleLimits();
271 
272         // Enable logging in the EAS service, so it starts up as early as possible.
273         Debug.updateLoggingFlags(this);
274     }
275 
276     /**
277      * Internal, utility method for logging.
278      * The calls to log() must be guarded with "if (Email.LOGD)" for performance reasons.
279      */
log(String message)280     public static void log(String message) {
281         Log.d(LOG_TAG, message);
282     }
283 
284     /**
285      * Update the time when the mailbox is refreshed
286      * @param mailboxId mailbox which need to be updated
287      */
updateMailboxRefreshTime(long mailboxId)288     public static void updateMailboxRefreshTime(long mailboxId) {
289         synchronized (sMailboxSyncTimes) {
290             sMailboxSyncTimes.put(mailboxId, System.currentTimeMillis());
291         }
292     }
293 
294     /**
295      * Check if the mailbox is need to be refreshed
296      * @param mailboxId mailbox checked the need of refreshing
297      * @return the need of refreshing
298      */
mailboxRequiresRefresh(long mailboxId)299     public static boolean mailboxRequiresRefresh(long mailboxId) {
300         synchronized (sMailboxSyncTimes) {
301             return
302                 !sMailboxSyncTimes.containsKey(mailboxId)
303                 || (System.currentTimeMillis() - sMailboxSyncTimes.get(mailboxId)
304                         > UPDATE_INTERVAL);
305         }
306     }
307 
308     /**
309      * Called by the accounts reconciler to notify that accounts have changed, or by  "Welcome"
310      * to clear the flag.
311      * @param setFlag true to set the notification flag, false to clear it
312      */
setNotifyUiAccountsChanged(boolean setFlag)313     public static synchronized void setNotifyUiAccountsChanged(boolean setFlag) {
314         sAccountsChangedNotification = setFlag;
315     }
316 
317     /**
318      * Called from activity onResume() functions to check for an accounts-changed condition, at
319      * which point they should finish() and jump to the Welcome activity.
320      */
getNotifyUiAccountsChanged()321     public static synchronized boolean getNotifyUiAccountsChanged() {
322         return sAccountsChangedNotification;
323     }
324 }
325