Merge branch '1193_uploader_layout' of https://github.com/owncloud/android into beta
[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.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.List;
29 import java.util.Vector;
30
31 import third_parties.daveKoeller.AlphanumComparator;
32
33 import com.owncloud.android.MainApp;
34 import com.owncloud.android.R;
35 import com.owncloud.android.datamodel.OCFile;
36 import com.owncloud.android.lib.resources.files.RemoteFile;
37
38 import android.accounts.Account;
39 import android.annotation.SuppressLint;
40 import android.content.Context;
41 import android.content.SharedPreferences;
42 import android.preference.PreferenceManager;
43 import android.net.Uri;
44 import android.os.Environment;
45 import android.os.StatFs;
46 import android.webkit.MimeTypeMap;
47
48
49 /**
50 * Static methods to help in access to local file system.
51 */
52 public class FileStorageUtils {
53 public static final Integer SORT_NAME = 0;
54 public static final Integer SORT_DATE = 1;
55 public static final Integer SORT_SIZE = 2;
56 public static Integer mSortOrder = SORT_NAME;
57 public static Boolean mSortAscending = true;
58
59
60 public static final String getSavePath(String accountName) {
61 File sdCard = Environment.getExternalStorageDirectory();
62 return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/" + Uri.encode(accountName, "@");
63 // 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
64 }
65
66 public static final String getDefaultSavePathFor(String accountName, OCFile file) {
67 return getSavePath(accountName) + file.getRemotePath();
68 }
69
70 public static final String getTemporalPath(String accountName) {
71 File sdCard = Environment.getExternalStorageDirectory();
72 return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/tmp/" + Uri.encode(accountName, "@");
73 // 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
74 }
75
76 @SuppressLint("NewApi")
77 public static final long getUsableSpace(String accountName) {
78 File savePath = Environment.getExternalStorageDirectory();
79 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
80 return savePath.getUsableSpace();
81
82 } else {
83 StatFs stats = new StatFs(savePath.getAbsolutePath());
84 return stats.getAvailableBlocks() * stats.getBlockSize();
85 }
86
87 }
88
89 public static final String getLogPath() {
90 return Environment.getExternalStorageDirectory() + File.separator + MainApp.getDataFolder() + File.separator + "log";
91 }
92
93 public static String getInstantUploadFilePath(Context context, String fileName) {
94 SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
95 String uploadPathdef = context.getString(R.string.instant_upload_path);
96 String uploadPath = pref.getString("instant_upload_path", uploadPathdef);
97 String value = uploadPath + OCFile.PATH_SEPARATOR + (fileName == null ? "" : fileName);
98 return value;
99 }
100
101 /**
102 * Gets the composed path when video is or must be stored
103 * @param context
104 * @param fileName: video file name
105 * @return String: video file path composed
106 */
107 public static String getInstantVideoUploadFilePath(Context context, String fileName) {
108 SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
109 String uploadVideoPathdef = context.getString(R.string.instant_upload_path);
110 String uploadVideoPath = pref.getString("instant_video_upload_path", uploadVideoPathdef);
111 String value = uploadVideoPath + OCFile.PATH_SEPARATOR + (fileName == null ? "" : fileName);
112 return value;
113 }
114
115 public static String getParentPath(String remotePath) {
116 String parentPath = new File(remotePath).getParent();
117 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
118 return parentPath;
119 }
120
121 /**
122 * Creates and populates a new {@link OCFile} object with the data read from the server.
123 *
124 * @param remote remote file read from the server (remote file or folder).
125 * @return New OCFile instance representing the remote resource described by remote.
126 */
127 public static OCFile fillOCFile(RemoteFile remote) {
128 OCFile file = new OCFile(remote.getRemotePath());
129 file.setCreationTimestamp(remote.getCreationTimestamp());
130 file.setFileLength(remote.getLength());
131 file.setMimetype(remote.getMimeType());
132 file.setModificationTimestamp(remote.getModifiedTimestamp());
133 file.setEtag(remote.getEtag());
134 file.setPermissions(remote.getPermissions());
135 file.setRemoteId(remote.getRemoteId());
136 return file;
137 }
138
139 /**
140 * Creates and populates a new {@link RemoteFile} object with the data read from an {@link OCFile}.
141 *
142 * @param ocFile OCFile
143 * @return New RemoteFile instance representing the resource described by ocFile.
144 */
145 public static RemoteFile fillRemoteFile(OCFile ocFile){
146 RemoteFile file = new RemoteFile(ocFile.getRemotePath());
147 file.setCreationTimestamp(ocFile.getCreationTimestamp());
148 file.setLength(ocFile.getFileLength());
149 file.setMimeType(ocFile.getMimetype());
150 file.setModifiedTimestamp(ocFile.getModificationTimestamp());
151 file.setEtag(ocFile.getEtag());
152 file.setPermissions(ocFile.getPermissions());
153 file.setRemoteId(ocFile.getRemoteId());
154 return file;
155 }
156
157 /**
158 * Sorts all filenames, regarding last user decision
159 */
160 public static Vector<OCFile> sortOcFolder(Vector<OCFile> files){
161 switch (mSortOrder){
162 case 0:
163 files = FileStorageUtils.sortOCFilesByName(files);
164 break;
165 case 1:
166 files = FileStorageUtils.sortOCFilesByDate(files);
167 break;
168 case 2:
169 // mFiles = FileStorageUtils.sortBySize(mSortAscending);
170 break;
171 }
172
173 return files;
174 }
175
176 /**
177 * Sorts all filenames, regarding last user decision
178 */
179 public static File[] sortLocalFolder(File[] files){
180 switch (mSortOrder){
181 case 0:
182 files = FileStorageUtils.sortLocalFilesByName(files);
183 break;
184 case 1:
185 files = FileStorageUtils.sortLocalFilesByDate(files);
186 break;
187 case 2:
188 // mFiles = FileStorageUtils.sortBySize(mSortAscending);
189 break;
190 }
191
192 return files;
193 }
194
195 /**
196 * Sorts list by Date
197 * @param files
198 */
199 public static Vector<OCFile> sortOCFilesByDate(Vector<OCFile> files){
200 final Integer val;
201 if (mSortAscending){
202 val = 1;
203 } else {
204 val = -1;
205 }
206
207 Collections.sort(files, new Comparator<OCFile>() {
208 public int compare(OCFile o1, OCFile o2) {
209 if (o1.isFolder() && o2.isFolder()) {
210 Long obj1 = o1.getModificationTimestamp();
211 return val * obj1.compareTo(o2.getModificationTimestamp());
212 }
213 else if (o1.isFolder()) {
214 return -1;
215 } else if (o2.isFolder()) {
216 return 1;
217 } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){
218 return 0;
219 } else {
220 Long obj1 = o1.getModificationTimestamp();
221 return val * obj1.compareTo(o2.getModificationTimestamp());
222 }
223 }
224 });
225
226 return files;
227 }
228
229 /**
230 * Sorts list by Date
231 * @param filesArray
232 */
233 public static File[] sortLocalFilesByDate(File[] filesArray){
234 final Integer val;
235 if (mSortAscending){
236 val = 1;
237 } else {
238 val = -1;
239 }
240
241 List<File> files = new ArrayList<File>(Arrays.asList(filesArray));
242
243 Collections.sort(files, new Comparator<File>() {
244 public int compare(File o1, File o2) {
245 if (o1.isDirectory() && o2.isDirectory()) {
246 Long obj1 = o1.lastModified();
247 return val * obj1.compareTo(o2.lastModified());
248 }
249 else if (o1.isDirectory()) {
250 return -1;
251 } else if (o2.isDirectory()) {
252 return 1;
253 } else if (o1.lastModified() == 0 || o2.lastModified() == 0){
254 return 0;
255 } else {
256 Long obj1 = o1.lastModified();
257 return val * obj1.compareTo(o2.lastModified());
258 }
259 }
260 });
261
262 File[] returnArray = new File[1];
263 return files.toArray(returnArray);
264 }
265
266 // /**
267 // * Sorts list by Size
268 // * @param sortAscending true: ascending, false: descending
269 // */
270 // public static Vector<OCFile> sortBySize(Vector<OCFile> files){
271 // final Integer val;
272 // if (mSortAscending){
273 // val = 1;
274 // } else {
275 // val = -1;
276 // }
277 //
278 // Collections.sort(files, new Comparator<OCFile>() {
279 // public int compare(OCFile o1, OCFile o2) {
280 // if (o1.isFolder() && o2.isFolder()) {
281 // Long obj1 = getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1)));
282 // return val * obj1.compareTo(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2))));
283 // }
284 // else if (o1.isFolder()) {
285 // return -1;
286 // } else if (o2.isFolder()) {
287 // return 1;
288 // } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){
289 // return 0;
290 // } else {
291 // Long obj1 = o1.getFileLength();
292 // return val * obj1.compareTo(o2.getFileLength());
293 // }
294 // }
295 // });
296 //
297 // return files;
298 // }
299
300 /**
301 * Sorts list by Name
302 * @param files files to sort
303 */
304 public static Vector<OCFile> sortOCFilesByName(Vector<OCFile> files){
305 final Integer val;
306 if (mSortAscending){
307 val = 1;
308 } else {
309 val = -1;
310 }
311
312 Collections.sort(files, new Comparator<OCFile>() {
313 public int compare(OCFile o1, OCFile o2) {
314 if (o1.isFolder() && o2.isFolder()) {
315 return val * new AlphanumComparator().compare(o1, o2);
316 } else if (o1.isFolder()) {
317 return -1;
318 } else if (o2.isFolder()) {
319 return 1;
320 }
321 return val * new AlphanumComparator().compare(o1, o2);
322 }
323 });
324
325 return files;
326 }
327
328 /**
329 * Sorts list by Name
330 * @param filesArray files to sort
331 */
332 public static File[] sortLocalFilesByName(File[] filesArray){
333 final Integer val;
334 if (mSortAscending){
335 val = 1;
336 } else {
337 val = -1;
338 }
339
340 List<File> files = new ArrayList<File>(Arrays.asList(filesArray));
341
342 Collections.sort(files, new Comparator<File>() {
343 public int compare(File o1, File o2) {
344 if (o1.isDirectory() && o2.isDirectory()) {
345 return val * o1.getPath().toLowerCase().compareTo(o2.getPath().toLowerCase());
346 } else if (o1.isDirectory()) {
347 return -1;
348 } else if (o2.isDirectory()) {
349 return 1;
350 }
351 return val * new AlphanumComparator().compare(o1.getPath().toLowerCase(),
352 o2.getPath().toLowerCase());
353 }
354 });
355
356 File[] returnArray = new File[1];
357 return files.toArray(returnArray);
358 }
359
360 /**
361 * Local Folder size
362 * @param dir File
363 * @return Size in bytes
364 */
365 public static long getFolderSize(File dir) {
366 if (dir.exists()) {
367 long result = 0;
368 File[] fileList = dir.listFiles();
369 for(int i = 0; i < fileList.length; i++) {
370 if(fileList[i].isDirectory()) {
371 result += getFolderSize(fileList[i]);
372 } else {
373 result += fileList[i].length();
374 }
375 }
376 return result;
377 }
378 return 0;
379 }
380
381 /**
382 * Mimetype String of a file
383 * @param path
384 * @return
385 */
386 public static String getMimeTypeFromName(String path) {
387 String extension = "";
388 int pos = path.lastIndexOf('.');
389 if (pos >= 0) {
390 extension = path.substring(pos + 1);
391 }
392 String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
393 return (result != null) ? result : "";
394 }
395
396 /**
397 * Scans the default location for saving local copies of files searching for
398 * a 'lost' file with the same full name as the {@link OCFile} received as
399 * parameter.
400 *
401 * This method helps to keep linked local copies of the files when the app is uninstalled, and then
402 * reinstalled in the device. OR after the cache of the app was deleted in system settings.
403 *
404 * The method is assuming that all the local changes in the file where synchronized in the past. This is dangerous,
405 * but assuming the contrary could lead to massive unnecessary synchronizations of downloaded file after deleting
406 * the app cache.
407 *
408 * This should be changed in the near future to avoid any chance of data loss, but we need to add some options
409 * to limit hard automatic synchronizations to wifi, unless the user wants otherwise.
410 *
411 * @param file File to associate a possible 'lost' local file.
412 * @param account Account holding file.
413 */
414 public static void searchForLocalFileInDefaultPath(OCFile file, Account account) {
415 if (file.getStoragePath() == null && !file.isFolder()) {
416 File f = new File(FileStorageUtils.getDefaultSavePathFor(account.name, file));
417 if (f.exists()) {
418 file.setStoragePath(f.getAbsolutePath());
419 file.setLastSyncDateForData(f.lastModified());
420 }
421 }
422 }
423
424 }