e5573b6ff6b5648207269a5f31e22eba3e44171f
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / OCFile.java
1 /**
2 * ownCloud Android client application
3 *
4 * Copyright (C) 2012 Bartek Przybylski
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.datamodel;
22
23 import android.content.ContentResolver;
24 import android.net.Uri;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.webkit.MimeTypeMap;
28
29 import com.owncloud.android.lib.common.utils.Log_OC;
30
31 import java.io.File;
32
33 import third_parties.daveKoeller.AlphanumComparator;
34 public class OCFile implements Parcelable, Comparable<OCFile> {
35
36 public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
37 @Override
38 public OCFile createFromParcel(Parcel source) {
39 return new OCFile(source);
40 }
41
42 @Override
43 public OCFile[] newArray(int size) {
44 return new OCFile[size];
45 }
46 };
47
48 private final static String PERMISSION_SHARED_WITH_ME = "S"; // TODO move to better location
49
50 public static final String PATH_SEPARATOR = "/";
51 public static final String ROOT_PATH = PATH_SEPARATOR;
52
53 private static final String TAG = OCFile.class.getSimpleName();
54
55 private long mId;
56 private long mParentId;
57 private long mLength;
58 private long mCreationTimestamp;
59 private long mModifiedTimestamp;
60 private long mModifiedTimestampAtLastSyncForData;
61 private String mRemotePath;
62 private String mLocalPath;
63 private String mMimeType;
64 private boolean mNeedsUpdating;
65 private long mLastSyncDateForProperties;
66 private long mLastSyncDateForData;
67 private boolean mFavorite;
68
69 private String mEtag;
70
71 private boolean mShareByLink;
72 private String mPublicLink;
73
74 private String mPermissions;
75 private String mRemoteId;
76
77 private boolean mNeedsUpdateThumbnail;
78
79 private boolean mIsDownloading;
80
81 private String mEtagInConflict; // Save file etag in the server, when there is a conflict. No conflict = null
82
83 private boolean mShareWithSharee;
84
85 /**
86 * URI to the local path of the file contents, if stored in the device; cached after first call
87 * to {@link #getStorageUri()}
88 */
89 private Uri mLocalUri;
90
91
92 /**
93 * Create new {@link OCFile} with given path.
94 * <p/>
95 * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'.
96 *
97 * @param path The remote path of the file.
98 */
99 public OCFile(String path) {
100 resetData();
101 mNeedsUpdating = false;
102 if (path == null || path.length() <= 0 || !path.startsWith(PATH_SEPARATOR)) {
103 throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path);
104 }
105 mRemotePath = path;
106 }
107
108 /**
109 * Reconstruct from parcel
110 *
111 * @param source The source parcel
112 */
113 private OCFile(Parcel source) {
114 mId = source.readLong();
115 mParentId = source.readLong();
116 mLength = source.readLong();
117 mCreationTimestamp = source.readLong();
118 mModifiedTimestamp = source.readLong();
119 mModifiedTimestampAtLastSyncForData = source.readLong();
120 mRemotePath = source.readString();
121 mLocalPath = source.readString();
122 mMimeType = source.readString();
123 mNeedsUpdating = source.readInt() == 0;
124 mFavorite = source.readInt() == 1;
125 mLastSyncDateForProperties = source.readLong();
126 mLastSyncDateForData = source.readLong();
127 mEtag = source.readString();
128 mShareByLink = source.readInt() == 1;
129 mPublicLink = source.readString();
130 mPermissions = source.readString();
131 mRemoteId = source.readString();
132 mNeedsUpdateThumbnail = source.readInt() == 1;
133 mIsDownloading = source.readInt() == 1;
134 mEtagInConflict = source.readString();
135 mShareWithSharee = source.readInt() == 1;
136
137 }
138
139 @Override
140 public void writeToParcel(Parcel dest, int flags) {
141 dest.writeLong(mId);
142 dest.writeLong(mParentId);
143 dest.writeLong(mLength);
144 dest.writeLong(mCreationTimestamp);
145 dest.writeLong(mModifiedTimestamp);
146 dest.writeLong(mModifiedTimestampAtLastSyncForData);
147 dest.writeString(mRemotePath);
148 dest.writeString(mLocalPath);
149 dest.writeString(mMimeType);
150 dest.writeInt(mNeedsUpdating ? 1 : 0);
151 dest.writeInt(mFavorite ? 1 : 0);
152 dest.writeLong(mLastSyncDateForProperties);
153 dest.writeLong(mLastSyncDateForData);
154 dest.writeString(mEtag);
155 dest.writeInt(mShareByLink ? 1 : 0);
156 dest.writeString(mPublicLink);
157 dest.writeString(mPermissions);
158 dest.writeString(mRemoteId);
159 dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
160 dest.writeInt(mIsDownloading ? 1 : 0);
161 dest.writeString(mEtagInConflict);
162 dest.writeInt(mShareWithSharee ? 1 : 0);
163 }
164
165 /**
166 * Gets the ID of the file
167 *
168 * @return the file ID
169 */
170 public long getFileId() {
171 return mId;
172 }
173
174 /**
175 * Returns the remote path of the file on ownCloud
176 *
177 * @return The remote path to the file
178 */
179 public String getRemotePath() {
180 return mRemotePath;
181 }
182
183 /**
184 * Can be used to check, whether or not this file exists in the database
185 * already
186 *
187 * @return true, if the file exists in the database
188 */
189 public boolean fileExists() {
190 return mId != -1;
191 }
192
193 /**
194 * Use this to find out if this file is a folder.
195 *
196 * @return true if it is a folder
197 */
198 public boolean isFolder() {
199 return mMimeType != null && mMimeType.equals("DIR");
200 }
201
202 /**
203 * Use this to check if this file is available locally
204 *
205 * @return true if it is
206 */
207 public boolean isDown() {
208 if (mLocalPath != null && mLocalPath.length() > 0) {
209 File file = new File(mLocalPath);
210 return (file.exists());
211 }
212 return false;
213 }
214
215 /**
216 * The path, where the file is stored locally
217 *
218 * @return The local path to the file
219 */
220 public String getStoragePath() {
221 return mLocalPath;
222 }
223
224 /**
225 * The URI to the file contents, if stored locally
226 *
227 * @return A URI to the local copy of the file, or NULL if not stored in the device
228 */
229 public Uri getStorageUri() {
230 if (mLocalPath == null || mLocalPath.length() == 0) {
231 return null;
232 }
233 if (mLocalUri == null) {
234 Uri.Builder builder = new Uri.Builder();
235 builder.scheme(ContentResolver.SCHEME_FILE);
236 builder.path(mLocalPath);
237 mLocalUri = builder.build();
238 }
239 return mLocalUri;
240 }
241
242 /**
243 * Can be used to set the path where the file is stored
244 *
245 * @param storage_path to set
246 */
247 public void setStoragePath(String storage_path) {
248 mLocalPath = storage_path;
249 mLocalUri = null;
250 }
251
252 /**
253 * Get a UNIX timestamp of the file creation time
254 *
255 * @return A UNIX timestamp of the time that file was created
256 */
257 public long getCreationTimestamp() {
258 return mCreationTimestamp;
259 }
260
261 /**
262 * Set a UNIX timestamp of the time the file was created
263 *
264 * @param creation_timestamp to set
265 */
266 public void setCreationTimestamp(long creation_timestamp) {
267 mCreationTimestamp = creation_timestamp;
268 }
269
270 /**
271 * Get a UNIX timestamp of the file modification time.
272 *
273 * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
274 * in the last synchronization of the properties of this file.
275 */
276 public long getModificationTimestamp() {
277 return mModifiedTimestamp;
278 }
279
280 /**
281 * Set a UNIX timestamp of the time the time the file was modified.
282 * <p/>
283 * To update with the value returned by the server in every synchronization of the properties
284 * of this file.
285 *
286 * @param modification_timestamp to set
287 */
288 public void setModificationTimestamp(long modification_timestamp) {
289 mModifiedTimestamp = modification_timestamp;
290 }
291
292
293 /**
294 * Get a UNIX timestamp of the file modification time.
295 *
296 * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
297 * in the last synchronization of THE CONTENTS of this file.
298 */
299 public long getModificationTimestampAtLastSyncForData() {
300 return mModifiedTimestampAtLastSyncForData;
301 }
302
303 /**
304 * Set a UNIX timestamp of the time the time the file was modified.
305 * <p/>
306 * To update with the value returned by the server in every synchronization of THE CONTENTS
307 * of this file.
308 *
309 * @param modificationTimestamp to set
310 */
311 public void setModificationTimestampAtLastSyncForData(long modificationTimestamp) {
312 mModifiedTimestampAtLastSyncForData = modificationTimestamp;
313 }
314
315
316 /**
317 * Returns the filename and "/" for the root directory
318 *
319 * @return The name of the file
320 */
321 public String getFileName() {
322 File f = new File(getRemotePath());
323 return f.getName().length() == 0 ? ROOT_PATH : f.getName();
324 }
325
326 /**
327 * Sets the name of the file
328 * <p/>
329 * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root
330 * directory
331 */
332 public void setFileName(String name) {
333 Log_OC.d(TAG, "OCFile name changin from " + mRemotePath);
334 if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) &&
335 !mRemotePath.equals(ROOT_PATH)) {
336 String parent = (new File(getRemotePath())).getParent();
337 parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
338 mRemotePath = parent + name;
339 if (isFolder()) {
340 mRemotePath += PATH_SEPARATOR;
341 }
342 Log_OC.d(TAG, "OCFile name changed to " + mRemotePath);
343 }
344 }
345
346 /**
347 * Can be used to get the Mimetype
348 *
349 * @return the Mimetype as a String
350 */
351 public String getMimetype() {
352 return mMimeType;
353 }
354
355 /**
356 * Used internally. Reset all file properties
357 */
358 private void resetData() {
359 mId = -1;
360 mRemotePath = null;
361 mParentId = 0;
362 mLocalPath = null;
363 mMimeType = null;
364 mLength = 0;
365 mCreationTimestamp = 0;
366 mModifiedTimestamp = 0;
367 mModifiedTimestampAtLastSyncForData = 0;
368 mLastSyncDateForProperties = 0;
369 mLastSyncDateForData = 0;
370 mFavorite = false;
371 mNeedsUpdating = false;
372 mEtag = null;
373 mShareByLink = false;
374 mPublicLink = null;
375 mPermissions = null;
376 mRemoteId = null;
377 mNeedsUpdateThumbnail = false;
378 mIsDownloading = false;
379 mEtagInConflict = null;
380 mShareWithSharee = false;
381 }
382
383 /**
384 * Sets the ID of the file
385 *
386 * @param file_id to set
387 */
388 public void setFileId(long file_id) {
389 mId = file_id;
390 }
391
392 /**
393 * Sets the Mime-Type of the
394 *
395 * @param mimetype to set
396 */
397 public void setMimetype(String mimetype) {
398 mMimeType = mimetype;
399 }
400
401 /**
402 * Sets the ID of the parent folder
403 *
404 * @param parent_id to set
405 */
406 public void setParentId(long parent_id) {
407 mParentId = parent_id;
408 }
409
410 /**
411 * Sets the file size in bytes
412 *
413 * @param file_len to set
414 */
415 public void setFileLength(long file_len) {
416 mLength = file_len;
417 }
418
419 /**
420 * Returns the size of the file in bytes
421 *
422 * @return The filesize in bytes
423 */
424 public long getFileLength() {
425 return mLength;
426 }
427
428 /**
429 * Returns the ID of the parent Folder
430 *
431 * @return The ID
432 */
433 public long getParentId() {
434 return mParentId;
435 }
436
437 /**
438 * Check, if this file needs updating
439 *
440 * @return
441 */
442 public boolean needsUpdatingWhileSaving() {
443 return mNeedsUpdating;
444 }
445
446 public boolean needsUpdateThumbnail() {
447 return mNeedsUpdateThumbnail;
448 }
449
450 public void setNeedsUpdateThumbnail(boolean needsUpdateThumbnail) {
451 this.mNeedsUpdateThumbnail = needsUpdateThumbnail;
452 }
453
454 public long getLastSyncDateForProperties() {
455 return mLastSyncDateForProperties;
456 }
457
458 public void setLastSyncDateForProperties(long lastSyncDate) {
459 mLastSyncDateForProperties = lastSyncDate;
460 }
461
462 public long getLastSyncDateForData() {
463 return mLastSyncDateForData;
464 }
465
466 public void setLastSyncDateForData(long lastSyncDate) {
467 mLastSyncDateForData = lastSyncDate;
468 }
469
470 public void setFavorite(boolean favorite) {
471 mFavorite = favorite;
472 }
473
474 public boolean isFavorite() {
475 return mFavorite;
476 }
477
478 @Override
479 public int describeContents() {
480 return super.hashCode();
481 }
482
483 @Override
484 public int compareTo(OCFile another) {
485 if (isFolder() && another.isFolder()) {
486 return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase());
487 } else if (isFolder()) {
488 return -1;
489 } else if (another.isFolder()) {
490 return 1;
491 }
492 return new AlphanumComparator().compare(this, another);
493 }
494
495 @Override
496 public boolean equals(Object o) {
497 if (o instanceof OCFile) {
498 OCFile that = (OCFile) o;
499 if (that != null) {
500 return this.mId == that.mId;
501 }
502 }
503
504 return false;
505 }
506
507 @Override
508 public String toString() {
509 String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " +
510 "parentId=%s, favorite=%s etag=%s]";
511 asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(),
512 mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mFavorite),
513 mEtag);
514 return asString;
515 }
516
517 public String getEtag() {
518 return mEtag;
519 }
520
521 public void setEtag(String etag) {
522 this.mEtag = (etag != null ? etag : "");
523 }
524
525
526 public boolean isSharedViaLink() {
527 return mShareByLink;
528 }
529
530 public void setShareViaLink(boolean shareByLink) {
531 this.mShareByLink = shareByLink;
532 }
533
534 public String getPublicLink() {
535 return mPublicLink;
536 }
537
538 public void setPublicLink(String publicLink) {
539 this.mPublicLink = publicLink;
540 }
541
542 public long getLocalModificationTimestamp() {
543 if (mLocalPath != null && mLocalPath.length() > 0) {
544 File f = new File(mLocalPath);
545 return f.lastModified();
546 }
547 return 0;
548 }
549
550 /**
551 * @return 'True' if the file contains audio
552 */
553 public boolean isAudio() {
554 return (mMimeType != null && mMimeType.startsWith("audio/"));
555 }
556
557 /**
558 * @return 'True' if the file contains video
559 */
560 public boolean isVideo() {
561 return (mMimeType != null && mMimeType.startsWith("video/"));
562 }
563
564 /**
565 * @return 'True' if the file contains an image
566 */
567 public boolean isImage() {
568 return ((mMimeType != null && mMimeType.startsWith("image/")) ||
569 getMimeTypeFromName().startsWith("image/"));
570 }
571
572 /**
573 * @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx)
574 */
575 public boolean isText() {
576 return ((mMimeType != null && mMimeType.startsWith("text/")) ||
577 getMimeTypeFromName().startsWith("text/"));
578 }
579
580 public String getMimeTypeFromName() {
581 String extension = "";
582 int pos = mRemotePath.lastIndexOf('.');
583 if (pos >= 0) {
584 extension = mRemotePath.substring(pos + 1);
585 }
586 String result = MimeTypeMap.getSingleton().
587 getMimeTypeFromExtension(extension.toLowerCase());
588 return (result != null) ? result : "";
589 }
590
591 /**
592 * @return 'True' if the file is hidden
593 */
594 public boolean isHidden() {
595 return getFileName().startsWith(".");
596 }
597
598 public String getPermissions() {
599 return mPermissions;
600 }
601
602 public void setPermissions(String permissions) {
603 this.mPermissions = permissions;
604 }
605
606 public String getRemoteId() {
607 return mRemoteId;
608 }
609
610 public void setRemoteId(String remoteId) {
611 this.mRemoteId = remoteId;
612 }
613
614 public boolean isDownloading() {
615 return mIsDownloading;
616 }
617
618 public void setDownloading(boolean isDownloading) {
619 this.mIsDownloading = isDownloading;
620 }
621
622 public String getEtagInConflict() {
623 return mEtagInConflict;
624 }
625
626 public void setEtagInConflict(String etagInConflict) {
627 mEtagInConflict = etagInConflict;
628 }
629
630 public boolean isSharedWithSharee() {
631 return mShareWithSharee;
632 }
633
634 public void setShareWithSharee(boolean shareWithSharee) {
635 this.mShareWithSharee = shareWithSharee;
636 }
637
638 public boolean isSharedWithMe() {
639 String permissions = getPermissions();
640 return (permissions != null && permissions.contains(PERMISSION_SHARED_WITH_ME));
641 }
642 }