Code cleanups
[pub/Android/ownCloud.git] / src / com / owncloud / android / utils / FileStorageUtils.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author David A. Velasco
5 * Copyright (C) 2015 ownCloud Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2,
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 package com.owncloud.android.utils;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.util.Collections;
30 import java.util.Comparator;
31 import java.util.Vector;
32
33 import third_parties.daveKoeller.AlphanumComparator;
34
35 import com.owncloud.android.MainApp;
36 import com.owncloud.android.R;
37 import com.owncloud.android.datamodel.OCFile;
38 import com.owncloud.android.lib.resources.files.RemoteFile;
39
40 import android.accounts.Account;
41 import android.annotation.SuppressLint;
42 import android.content.Context;
43 import android.content.SharedPreferences;
44 import android.preference.PreferenceManager;
45 import android.net.Uri;
46 import android.os.StatFs;
47 import android.webkit.MimeTypeMap;
48
49
50 /**
51 * Static methods to help in access to local file system.
52 */
53 public class FileStorageUtils {
54 public static final Integer SORT_NAME = 0;
55 public static final Integer SORT_DATE = 1;
56 public static final Integer SORT_SIZE = 2;
57 public static Integer mSortOrder = SORT_NAME;
58 public static Boolean mSortAscending = true;
59
60
61 public static final String getSavePath(String accountName) {
62 // File sdCard = Environment.getExternalStorageDirectory();
63
64 return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + Uri.encode(accountName, "@");
65 // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B
66 }
67
68 public static final String getDefaultSavePathFor(String accountName, OCFile file) {
69 return getSavePath(accountName) + file.getRemotePath();
70 }
71
72 public static final String getTemporalPath(String accountName) {
73 return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + "tmp" + File.separator + Uri.encode(accountName, "@");
74 // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B
75 }
76
77 @SuppressLint("NewApi")
78 public static final long getUsableSpace(String accountName) {
79 File savePath = new File(MainApp.getStoragePath());
80 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
81 return savePath.getUsableSpace();
82
83 } else {
84 StatFs stats = new StatFs(savePath.getAbsolutePath());
85 return stats.getAvailableBlocks() * stats.getBlockSize();
86 }
87
88 }
89
90 public static final String getLogPath() {
91 return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + "log";
92 }
93
94 public static String getInstantUploadFilePath(Context context, String fileName) {
95 SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
96 String uploadPathdef = context.getString(R.string.instant_upload_path);
97 String uploadPath = pref.getString("instant_upload_path", uploadPathdef);
98 String value = uploadPath + OCFile.PATH_SEPARATOR + (fileName == null ? "" : fileName);
99 return value;
100 }
101
102 /**
103 * Gets the composed path when video is or must be stored
104 * @param context
105 * @param fileName: video file name
106 * @return String: video file path composed
107 */
108 public static String getInstantVideoUploadFilePath(Context context, String fileName) {
109 SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
110 String uploadVideoPathdef = context.getString(R.string.instant_upload_path);
111 String uploadVideoPath = pref.getString("instant_video_upload_path", uploadVideoPathdef);
112 String value = uploadVideoPath + OCFile.PATH_SEPARATOR + (fileName == null ? "" : fileName);
113 return value;
114 }
115
116 public static String getParentPath(String remotePath) {
117 String parentPath = new File(remotePath).getParent();
118 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
119 return parentPath;
120 }
121
122 /**
123 * Creates and populates a new {@link OCFile} object with the data read from the server.
124 *
125 * @param remote remote file read from the server (remote file or folder).
126 * @return New OCFile instance representing the remote resource described by remote.
127 */
128 public static OCFile fillOCFile(RemoteFile remote) {
129 OCFile file = new OCFile(remote.getRemotePath());
130 file.setCreationTimestamp(remote.getCreationTimestamp());
131 file.setFileLength(remote.getLength());
132 file.setMimetype(remote.getMimeType());
133 file.setModificationTimestamp(remote.getModifiedTimestamp());
134 file.setEtag(remote.getEtag());
135 file.setPermissions(remote.getPermissions());
136 file.setRemoteId(remote.getRemoteId());
137 return file;
138 }
139
140 /**
141 * Creates and populates a new {@link RemoteFile} object with the data read from an {@link OCFile}.
142 *
143 * @param ocFile OCFile
144 * @return New RemoteFile instance representing the resource described by ocFile.
145 */
146 public static RemoteFile fillRemoteFile(OCFile ocFile){
147 RemoteFile file = new RemoteFile(ocFile.getRemotePath());
148 file.setCreationTimestamp(ocFile.getCreationTimestamp());
149 file.setLength(ocFile.getFileLength());
150 file.setMimeType(ocFile.getMimetype());
151 file.setModifiedTimestamp(ocFile.getModificationTimestamp());
152 file.setEtag(ocFile.getEtag());
153 file.setPermissions(ocFile.getPermissions());
154 file.setRemoteId(ocFile.getRemoteId());
155 return file;
156 }
157
158 /**
159 * Sorts all filenames, regarding last user decision
160 */
161 public static Vector<OCFile> sortFolder(Vector<OCFile> files){
162 switch (mSortOrder){
163 case 0:
164 files = FileStorageUtils.sortByName(files);
165 break;
166 case 1:
167 files = FileStorageUtils.sortByDate(files);
168 break;
169 case 2:
170 // mFiles = FileStorageUtils.sortBySize(mSortAscending);
171 break;
172 }
173
174 return files;
175 }
176
177 /**
178 * Sorts list by Date
179 * @param files
180 */
181 public static Vector<OCFile> sortByDate(Vector<OCFile> files){
182 final Integer val;
183 if (mSortAscending){
184 val = 1;
185 } else {
186 val = -1;
187 }
188
189 Collections.sort(files, new Comparator<OCFile>() {
190 public int compare(OCFile o1, OCFile o2) {
191 if (o1.isFolder() && o2.isFolder()) {
192 Long obj1 = o1.getModificationTimestamp();
193 return val * obj1.compareTo(o2.getModificationTimestamp());
194 }
195 else if (o1.isFolder()) {
196 return -1;
197 } else if (o2.isFolder()) {
198 return 1;
199 } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){
200 return 0;
201 } else {
202 Long obj1 = o1.getModificationTimestamp();
203 return val * obj1.compareTo(o2.getModificationTimestamp());
204 }
205 }
206 });
207
208 return files;
209 }
210
211 // /**
212 // * Sorts list by Size
213 // * @param sortAscending true: ascending, false: descending
214 // */
215 // public static Vector<OCFile> sortBySize(Vector<OCFile> files){
216 // final Integer val;
217 // if (mSortAscending){
218 // val = 1;
219 // } else {
220 // val = -1;
221 // }
222 //
223 // Collections.sort(files, new Comparator<OCFile>() {
224 // public int compare(OCFile o1, OCFile o2) {
225 // if (o1.isFolder() && o2.isFolder()) {
226 // Long obj1 = getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1)));
227 // return val * obj1.compareTo(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2))));
228 // }
229 // else if (o1.isFolder()) {
230 // return -1;
231 // } else if (o2.isFolder()) {
232 // return 1;
233 // } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){
234 // return 0;
235 // } else {
236 // Long obj1 = o1.getFileLength();
237 // return val * obj1.compareTo(o2.getFileLength());
238 // }
239 // }
240 // });
241 //
242 // return files;
243 // }
244
245 /**
246 * Sorts list by Name
247 * @param files files to sort
248 */
249 public static Vector<OCFile> sortByName(Vector<OCFile> files){
250 final Integer val;
251 if (mSortAscending){
252 val = 1;
253 } else {
254 val = -1;
255 }
256
257 Collections.sort(files, new Comparator<OCFile>() {
258 public int compare(OCFile o1, OCFile o2) {
259 if (o1.isFolder() && o2.isFolder()) {
260 return val * new AlphanumComparator().compare(o1, o2);
261 } else if (o1.isFolder()) {
262 return -1;
263 } else if (o2.isFolder()) {
264 return 1;
265 }
266 return val * new AlphanumComparator().compare(o1, o2);
267 }
268 });
269
270 return files;
271 }
272
273 /**
274 * Local Folder size
275 * @param dir File
276 * @return Size in bytes
277 */
278 public static long getFolderSize(File dir) {
279 if (dir.exists()) {
280 long result = 0;
281 for (File f : dir.listFiles()) {
282 if (f.isDirectory())
283 result += getFolderSize(f);
284 else
285 result += f.length();
286 }
287 return result;
288 }
289 return 0;
290 }
291
292 /**
293 * Mimetype String of a file
294 * @param path
295 * @return
296 */
297 public static String getMimeTypeFromName(String path) {
298 String extension = "";
299 int pos = path.lastIndexOf('.');
300 if (pos >= 0) {
301 extension = path.substring(pos + 1);
302 }
303 String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
304 return (result != null) ? result : "";
305 }
306
307 /**
308 * Scans the default location for saving local copies of files searching for
309 * a 'lost' file with the same full name as the {@link OCFile} received as
310 * parameter.
311 *
312 * This method helps to keep linked local copies of the files when the app is uninstalled, and then
313 * reinstalled in the device. OR after the cache of the app was deleted in system settings.
314 *
315 * The method is assuming that all the local changes in the file where synchronized in the past. This is dangerous,
316 * but assuming the contrary could lead to massive unnecessary synchronizations of downloaded file after deleting
317 * the app cache.
318 *
319 * This should be changed in the near future to avoid any chance of data loss, but we need to add some options
320 * to limit hard automatic synchronizations to wifi, unless the user wants otherwise.
321 *
322 * @param file File to associate a possible 'lost' local file.
323 * @param account Account holding file.
324 */
325 public static void searchForLocalFileInDefaultPath(OCFile file, Account account) {
326 if (file.getStoragePath() == null && !file.isFolder()) {
327 File f = new File(FileStorageUtils.getDefaultSavePathFor(account.name, file));
328 if (f.exists()) {
329 file.setStoragePath(f.getAbsolutePath());
330 file.setLastSyncDateForData(f.lastModified());
331 }
332 }
333 }
334
335 public static boolean copyFile(File src, File target) {
336 boolean ret = true;
337
338 InputStream in = null;
339 OutputStream out = null;
340
341 try {
342 in = new FileInputStream(src);
343 out = new FileOutputStream(target);
344 byte[] buf = new byte[1024];
345 int len;
346 while ((len = in.read(buf)) > 0) {
347 out.write(buf, 0, len);
348 }
349 } catch (IOException ex) {
350 ret = false;
351 } finally {
352 if (in != null) try {
353 in.close();
354 } catch (IOException e) {
355 e.printStackTrace(System.err);
356 }
357 if (out != null) try {
358 out.close();
359 } catch (IOException e) {
360 e.printStackTrace(System.err);
361 }
362 }
363
364 return ret;
365 }
366
367 }