Home | History | Annotate | Download | only in browse
      1 /*
      2  * Copyright (C) 2013 Google Inc.
      3  * Licensed to The Android Open Source Project.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mail.browse;
     19 
     20 import android.content.AsyncTaskLoader;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.net.Uri;
     25 
     26 import com.android.emailcommon.TempDirectory;
     27 import com.android.emailcommon.internet.MimeMessage;
     28 import com.android.emailcommon.mail.MessagingException;
     29 import com.android.mail.utils.LogTag;
     30 import com.android.mail.utils.LogUtils;
     31 
     32 import java.io.File;
     33 import java.io.FileNotFoundException;
     34 import java.io.IOException;
     35 import java.io.InputStream;
     36 
     37 /**
     38  * Loader that builds a ConversationMessage from an EML file Uri.
     39  */
     40 public class EmlMessageLoader extends AsyncTaskLoader<ConversationMessage> {
     41     private static final String LOG_TAG = LogTag.getLogTag();
     42 
     43     private Uri mEmlFileUri;
     44     private ConversationMessage mMessage;
     45 
     46     public EmlMessageLoader(Context context, Uri emlFileUri) {
     47         super(context);
     48         mEmlFileUri = emlFileUri;
     49     }
     50 
     51     @Override
     52     public ConversationMessage loadInBackground() {
     53         final Context context = getContext();
     54         TempDirectory.setTempDirectory(context);
     55         final ContentResolver resolver = context.getContentResolver();
     56         final InputStream stream;
     57         try {
     58             stream = resolver.openInputStream(mEmlFileUri);
     59         } catch (FileNotFoundException e) {
     60             LogUtils.e(LOG_TAG, e, "Could not find eml file at uri: %s", mEmlFileUri);
     61             return null;
     62         }
     63 
     64         final MimeMessage mimeMessage;
     65         final ConversationMessage convMessage;
     66         try {
     67             mimeMessage = new MimeMessage(stream);
     68             convMessage = new ConversationMessage(context, mimeMessage, mEmlFileUri);
     69         } catch (IOException e) {
     70             LogUtils.e(LOG_TAG, e, "Could not read eml file");
     71             return null;
     72         } catch (MessagingException e) {
     73             LogUtils.e(LOG_TAG, e, "Error in parsing eml file");
     74             return null;
     75         } finally {
     76             try {
     77                 stream.close();
     78             } catch (IOException e) {
     79                 return null;
     80             }
     81 
     82             // delete temp files created during parsing
     83             final File[] cacheFiles = TempDirectory.getTempDirectory().listFiles();
     84             for (final File file : cacheFiles) {
     85                 if (file.getName().startsWith("body")) {
     86                     file.delete();
     87                 }
     88             }
     89 
     90         }
     91 
     92         return convMessage;
     93     }
     94 
     95     /**
     96      * Called when there is new data to deliver to the client.  The
     97      * super class will take care of delivering it; the implementation
     98      * here just adds a little more logic.
     99      */
    100     @Override
    101     public void deliverResult(ConversationMessage result) {
    102         if (isReset()) {
    103             // An async query came in while the loader is stopped.  We
    104             // don't need the result.
    105             if (result != null) {
    106                 onReleaseResources(result);
    107             }
    108             return;
    109         }
    110         ConversationMessage oldMessage = mMessage;
    111         mMessage = result;
    112 
    113         if (isStarted()) {
    114             // If the Loader is currently started, we can immediately
    115             // deliver its results.
    116             super.deliverResult(result);
    117         }
    118 
    119         // At this point we can release the resources associated with
    120         // 'oldMessage' if needed; now that the new result is delivered we
    121         // know that it is no longer in use.
    122         if (oldMessage != null && oldMessage != mMessage) {
    123             onReleaseResources(oldMessage);
    124         }
    125     }
    126 
    127     /**
    128      * Handles a request to start the Loader.
    129      */
    130     @Override
    131     protected void onStartLoading() {
    132         if (mMessage != null) {
    133             // If we currently have a result available, deliver it immediately.
    134             deliverResult(mMessage);
    135         }
    136 
    137         if (takeContentChanged() || mMessage == null) {
    138             // If the data has changed since the last time it was loaded
    139             // or is not currently available, start a load.
    140             forceLoad();
    141         }
    142     }
    143 
    144     /**
    145      * Handles a request to stop the Loader.
    146      */
    147     @Override protected void onStopLoading() {
    148         // Attempt to cancel the current load task if possible.
    149         cancelLoad();
    150     }
    151 
    152     /**
    153      * Handles a request to cancel a load.
    154      */
    155     @Override
    156     public void onCanceled(ConversationMessage result) {
    157         super.onCanceled(result);
    158 
    159         // At this point we can release the resources associated with
    160         // the message, if needed.
    161         if (result != null) {
    162             onReleaseResources(result);
    163         }
    164     }
    165 
    166     /**
    167      * Handles a request to completely reset the Loader.
    168      */
    169     @Override
    170     protected void onReset() {
    171         super.onReset();
    172 
    173         // Ensure the loader is stopped
    174         onStopLoading();
    175 
    176         // At this point we can release the resources associated with
    177         // the message, if needed.
    178         if (mMessage != null) {
    179             onReleaseResources(mMessage);
    180             mMessage = null;
    181         }
    182     }
    183 
    184 
    185     /**
    186      * Helper function to take care of releasing resources associated
    187      * with an actively loaded data set.
    188      */
    189     protected void onReleaseResources(ConversationMessage message) {
    190         // if this eml message had attachments, start a service to clean up the cache files
    191         if (message.attachmentListUri != null) {
    192             final Intent intent = new Intent(Intent.ACTION_DELETE);
    193             intent.setClass(getContext(), EmlTempFileDeletionService.class);
    194             intent.setData(message.attachmentListUri);
    195 
    196             getContext().startService(intent);
    197         }
    198     }
    199 }
    200