package com.fsck.k9.provider;


import java.io.File;
import java.io.IOException;
import java.util.Date;

import android.content.Context;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import android.util.Log;

import com.fsck.k9.BuildConfig;
import com.fsck.k9.K9;
import com.fsck.k9.service.FileProviderInterface;


public class DecryptedFileProvider extends FileProvider {
    private static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".decryptedfileprovider";
    private static final String DECRYPTED_CACHE_DIRECTORY = "decrypted";


    public static final long FILE_DELETE_THRESHOLD_MILLISECONDS = 15 * 60 * 1000;


    @Override
    public String getType(Uri uri) {
        return uri.getQueryParameter("mime_type");
    }

    public static FileProviderInterface getFileProviderInterface(final Context context) {
        return new FileProviderInterface() {
            @Override
            public File createProvidedFile() throws IOException {
                File decryptedTempDirectory = getDecryptedTempDirectory(context);
                return File.createTempFile("decrypted-", null, decryptedTempDirectory);
            }

            @Override
            public Uri getUriForProvidedFile(File file, String mimeType) throws IOException {
                Uri uri = FileProvider.getUriForFile(context, AUTHORITY, file);
                return uri.buildUpon().appendQueryParameter("mime_type", mimeType).build();
            }
        };
    }

    public static boolean deleteOldTemporaryFiles(Context context) {
        File tempDirectory = getDecryptedTempDirectory(context);
        boolean allFilesDeleted = true;
        for (File tempFile : tempDirectory.listFiles()) {
            if (tempFile.lastModified() < new Date().getTime() - FILE_DELETE_THRESHOLD_MILLISECONDS) {
                boolean fileDeleted = tempFile.delete();
                if (!fileDeleted) {
                    Log.e(K9.LOG_TAG, "Failed to delete temporary file");
                    // TODO really do this? might cause our service to stay up indefinitely if a file can't be deleted
                    allFilesDeleted = false;
                }
            } else {
                allFilesDeleted = false;
            }
        }

        return allFilesDeleted;
    }

    private static File getDecryptedTempDirectory(Context context) {
        File directory = new File(context.getCacheDir(), DECRYPTED_CACHE_DIRECTORY);
        if (!directory.exists()) {
            if (!directory.mkdir()) {
                Log.e(K9.LOG_TAG, "Error creating directory: " + directory.getAbsolutePath());
            }
        }

        return directory;
    }
}

@@ -125,39 +125,195 @@
 ent.
-Context;%0Aimport android.net.Uri
+BroadcastReceiver;%0Aimport android.content.Context;%0Aimport android.content.Intent;%0Aimport android.content.IntentFilter;%0Aimport android.net.Uri;%0Aimport android.support.annotation.MainThread
 ;%0Aim
@@ -721,28 +721,27 @@
 ypted%22;%0A
-%0A%0A
     p
-ublic
+rivate
  static 
@@ -792,10 +792,9 @@
 S = 
-15
+3
  * 6
@@ -805,16 +805,73 @@
 1000;%0A%0A%0A
+    private static boolean receiverRegistered = false;%0A%0A%0A
     @Ove
@@ -1036,22 +1036,16 @@
 terface(
-final 
 Context 
@@ -1046,32 +1046,109 @@
 ntext context) %7B
+%0A        final Context applicationContext = context.getApplicationContext();%0A
 %0A        return 
@@ -1257,32 +1257,97 @@
 s IOException %7B%0A
+                registerFileCleanupReceiver(applicationContext);%0A
                 
@@ -1394,33 +1394,44 @@
 edTempDirectory(
-c
+applicationC
 ontext);%0A       
@@ -1691,25 +1691,36 @@
 tUriForFile(
-c
+applicationC
 ontext, AUTH
@@ -2031,16 +2031,108 @@
 = true;%0A
+        long deletionThreshold = new Date().getTime() - FILE_DELETE_THRESHOLD_MILLISECONDS;%0A
         
@@ -2193,20 +2193,36 @@
         
-if (
+long lastModified = 
 tempFile
@@ -2240,68 +2240,58 @@
 ed()
- %3C new Date().getTime() - FILE_DELETE_THRESHOLD_MILLISECONDS
+;%0A            if (lastModified %3C deletionThreshold
 ) %7B%0A
@@ -3143,11 +3143,1077 @@
 y;%0A    %7D
+%0A%0A    @MainThread // no need to synchronize for receiverRegistered%0A    private static void registerFileCleanupReceiver(Context context) %7B%0A        if (receiverRegistered) %7B%0A            return;%0A        %7D%0A        receiverRegistered = true;%0A        IntentFilter intentFilter = new IntentFilter();%0A        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);%0A        context.registerReceiver(new DecryptedFileProviderCleanupReceiver(), intentFilter);%0A    %7D%0A%0A    private static class DecryptedFileProviderCleanupReceiver extends BroadcastReceiver %7B%0A        @Override%0A        @MainThread%0A        public void onReceive(Context context, Intent intent) %7B%0A            if (!Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) %7B%0A                throw new IllegalArgumentException(%22onReceive called with action that isn't screen off!%22);%0A            %7D%0A%0A            boolean allFilesDeleted = deleteOldTemporaryFiles(context);%0A            if (allFilesDeleted) %7B%0A                context.unregisterReceiver(this);%0A                receiverRegistered = false;%0A            %7D%0A        %7D%0A    %7D
 %0A%7D%0A

add DecryptedFileProviderCleanupReceiver to clean up temp files on screen off