Home | History | Annotate | Download | only in email
      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 
    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 
    183     public static int getAccountColorResourceId(long accountId) {
    184         return ACCOUNT_COLOR_CHIP_RES_IDS[getColorIndexFromAccountId(accountId)];
    185     }
    186 
    187     public static int getAccountColor(long accountId) {
    188         return ACCOUNT_COLOR_CHIP_RGBS[getColorIndexFromAccountId(accountId)];
    189     }
    190 
    191     public static void setTempDirectory(Context context) {
    192         sTempDirectory = context.getCacheDir();
    193     }
    194 
    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      */
    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 
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    321     public static synchronized boolean getNotifyUiAccountsChanged() {
    322         return sAccountsChangedNotification;
    323     }
    324 }
    325