Added Android code
[wl-app.git] / Android / app / src / main / java / com / moiseum / wolnelektury / connection / downloads / FileCacheUtils.java
1 package com.moiseum.wolnelektury.connection.downloads;
2
3 import android.os.Environment;
4 import android.support.annotation.NonNull;
5 import android.util.Log;
6
7 import com.moiseum.wolnelektury.base.WLApplication;
8 import com.moiseum.wolnelektury.connection.models.MediaModel;
9
10 import org.greenrobot.eventbus.EventBus;
11
12 import java.io.File;
13 import java.io.FileOutputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.OutputStream;
17 import java.util.List;
18
19 import io.reactivex.Completable;
20 import okhttp3.ResponseBody;
21
22 import static android.os.Environment.isExternalStorageRemovable;
23
24 /**
25  * Created by Piotr Ostrowski on 10.05.2017.
26  */
27
28 public class FileCacheUtils {
29
30         private static final String FILES_CACHE = "FilesCache";
31         private static final int BUFFER_SIZE = 4096;
32         private static final long PROGRESS_UPDATE_RATE = 10;
33         private static final String TAG = FileCacheUtils.class.getSimpleName();
34
35         private FileCacheUtils() {
36                 // nop.
37         }
38
39         public static String getCachedFileForUrl(String url) {
40                 File cachedFile = new File(getCurrentCachePath() + File.separator + url.hashCode());
41                 if (cachedFile.exists()) {
42                         return cachedFile.getAbsolutePath();
43                 } else {
44                         return null;
45                 }
46         }
47
48         public static boolean deleteFileForUrl(String url) {
49                 File cachedFile = new File(getCurrentCachePath() + File.separator + url.hashCode());
50                 if (cachedFile.exists()) {
51                         return cachedFile.delete();
52                 } else {
53                         Log.e(TAG, "There is no file to be removed: " + url);
54                         return false;
55                 }
56         }
57
58         public static boolean writeResponseBodyToDiskCache(ResponseBody body, String fileUrl) {
59                 try {
60                         String cachePath = getCurrentCachePath();
61                         File fileCacheDir = new File(cachePath);
62                         File downloadFile = new File(cachePath + File.separator + fileUrl.hashCode() + ".download");
63                         createCacheFolderAndFile(cachePath, fileCacheDir, downloadFile);
64
65                         InputStream inputStream = null;
66                         OutputStream outputStream = null;
67
68                         try {
69                                 byte[] fileReader = new byte[BUFFER_SIZE];
70                                 long fileSize = body.contentLength();
71                                 long fileSizeDownloaded = 0;
72
73                                 inputStream = body.byteStream();
74                                 outputStream = new FileOutputStream(downloadFile);
75
76                                 int updateRate = 0;
77                                 while (true) {
78                                         int read = inputStream.read(fileReader);
79                                         if (read == -1) {
80                                                 break;
81                                         }
82
83                                         outputStream.write(fileReader, 0, read);
84                                         fileSizeDownloaded += read;
85                                         if (updateRate++ % PROGRESS_UPDATE_RATE == 0) {
86                                                 EventBus.getDefault().post(new DownloadProgressEvent(fileUrl, fileSizeDownloaded, fileSize));
87                                         }
88                                 }
89                                 outputStream.flush();
90
91                                 File audioFileDest = new File(cachePath + File.separator + fileUrl.hashCode());
92                                 boolean renamed = downloadFile.renameTo(audioFileDest);
93                                 if (!renamed) {
94                                         throw new IOException("Failed to rename downloaded file: " + audioFileDest.getAbsolutePath());
95                                 }
96                                 return true;
97                         } catch (IOException e) {
98                                 Log.e(TAG, "Failed to save file to cache: " + fileUrl, e);
99                                 downloadFile.delete();
100                                 return false;
101                         } finally {
102                                 if (inputStream != null) {
103                                         inputStream.close();
104                                 }
105                                 if (outputStream != null) {
106                                         outputStream.close();
107                                 }
108                         }
109                 } catch (IOException e) {
110                         Log.e(TAG, "File creation or streaming closure failed", e);
111                         return false;
112                 }
113         }
114
115         private static void createCacheFolderAndFile(String cachePath, File audioCacheDir, File audioFile) throws IOException {
116                 if (!audioCacheDir.exists()) {
117                         boolean result = audioCacheDir.mkdir();
118                         if (!result) {
119                                 throw new IOException("Failed to create AudioCache Dir.");
120                         }
121                 }
122                 if (!audioFile.exists()) {
123                         boolean result = audioFile.createNewFile();
124                         if (!result) {
125                                 throw new IOException("Failed to create file in path: " + audioFile.getAbsolutePath());
126                         }
127                 }
128         }
129
130         @NonNull
131         private static String getCurrentCachePath() {
132                 File externalCacheDir = WLApplication.getInstance().getApplicationContext().getExternalCacheDir();
133                 String cachePath = (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !isExternalStorageRemovable()) &&
134                                 externalCacheDir != null ? externalCacheDir.getPath() : WLApplication.getInstance().getCacheDir().getPath();
135                 return cachePath + File.separator + FILES_CACHE;
136         }
137
138         public static Completable deleteAudiobookFiles(List<String> fileUrls) {
139                 return Completable.fromAction(() -> {
140                         for (String fileUrl : fileUrls) {
141                                 boolean deleted = deleteFileForUrl(fileUrl);
142                                 if (!deleted) {
143                                         Log.e(TAG, "Failed to delete file " + FileCacheUtils.getCachedFileForUrl(fileUrl));
144                                 }
145                         }
146                 });
147         }
148
149         public static Completable deleteEbookFile(final String epubUrl) {
150                 return Completable.fromAction(() -> deleteFileForUrl(epubUrl));
151         }
152
153         /**
154          * Event indicating progress.
155          */
156         public static class DownloadProgressEvent {
157
158                 private String fileUrl;
159                 private long downloaded;
160                 private long total;
161
162                 public DownloadProgressEvent(String fileUrl, long downloaded, long total) {
163                         this.fileUrl = fileUrl;
164                         this.downloaded = downloaded;
165                         this.total = total;
166                 }
167
168                 public String getFileUrl() {
169                         return fileUrl;
170                 }
171
172                 public long getDownloaded() {
173                         return downloaded;
174                 }
175
176                 public long getTotal() {
177                         return total;
178                 }
179         }
180 }