2 * ownCloud Android client application
4 * @author Bartek Przybylski
5 * @author David A. Velasco
6 * Copyright (C) 2012 Bartek Przybylski
7 * Copyright (C) 2015 ownCloud Inc.
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2,
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 package com
.owncloud
.android
.datamodel
;
25 import android
.content
.ContentResolver
;
26 import android
.net
.Uri
;
27 import android
.os
.Parcel
;
28 import android
.os
.Parcelable
;
29 import android
.webkit
.MimeTypeMap
;
31 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
;
35 import third_parties
.daveKoeller
.AlphanumComparator
;
36 public class OCFile
implements Parcelable
, Comparable
<OCFile
> {
38 public static final Parcelable
.Creator CREATOR
= new Parcelable
.Creator() {
39 public OCFile
createFromParcel(Parcel source
) {
40 return new OCFile(source
);
43 public OCFile
[] newArray(int size
) {
44 return new OCFile
[size
];
48 private final static String PERMISSION_SHARED_WITH_ME
= "S"; // TODO move to better location
50 public static final String PATH_SEPARATOR
= "/";
51 public static final String ROOT_PATH
= PATH_SEPARATOR
;
53 private static final String TAG
= OCFile
.class.getSimpleName();
56 private long mParentId
;
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
;
71 private boolean mShareByLink
;
72 private String mPublicLink
;
74 private String mPermissions
;
75 private String mRemoteId
;
77 private boolean mNeedsUpdateThumbnail
;
79 private boolean mIsDownloading
;
81 private boolean mShowGridView
;
83 private String mEtagInConflict
; // Save file etag in the server, when there is a conflict. No conflict = null
85 private boolean mShareWithSharee
;
88 * URI to the local path of the file contents, if stored in the device; cached after first call
89 * to {@link #getStorageUri()}
91 private Uri mLocalUri
;
95 * Create new {@link OCFile} with given path.
97 * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'.
99 * @param path The remote path of the file.
101 public OCFile(String path
) {
103 mNeedsUpdating
= false
;
104 if (path
== null
|| path
.length() <= 0 || !path
.startsWith(PATH_SEPARATOR
)) {
105 throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path
);
111 * Reconstruct from parcel
113 * @param source The source parcel
115 private OCFile(Parcel source
) {
116 mId
= source
.readLong();
117 mParentId
= source
.readLong();
118 mLength
= source
.readLong();
119 mCreationTimestamp
= source
.readLong();
120 mModifiedTimestamp
= source
.readLong();
121 mModifiedTimestampAtLastSyncForData
= source
.readLong();
122 mRemotePath
= source
.readString();
123 mLocalPath
= source
.readString();
124 mMimeType
= source
.readString();
125 mNeedsUpdating
= source
.readInt() == 0;
126 mFavorite
= source
.readInt() == 1;
127 mLastSyncDateForProperties
= source
.readLong();
128 mLastSyncDateForData
= source
.readLong();
129 mEtag
= source
.readString();
130 mShareByLink
= source
.readInt() == 1;
131 mPublicLink
= source
.readString();
132 mPermissions
= source
.readString();
133 mRemoteId
= source
.readString();
134 mNeedsUpdateThumbnail
= source
.readInt() == 1;
135 mIsDownloading
= source
.readInt() == 1;
136 mEtagInConflict
= source
.readString();
137 mShareWithSharee
= source
.readInt() == 1;
142 public void writeToParcel(Parcel dest
, int flags
) {
144 dest
.writeLong(mParentId
);
145 dest
.writeLong(mLength
);
146 dest
.writeLong(mCreationTimestamp
);
147 dest
.writeLong(mModifiedTimestamp
);
148 dest
.writeLong(mModifiedTimestampAtLastSyncForData
);
149 dest
.writeString(mRemotePath
);
150 dest
.writeString(mLocalPath
);
151 dest
.writeString(mMimeType
);
152 dest
.writeInt(mNeedsUpdating ?
1 : 0);
153 dest
.writeInt(mFavorite ?
1 : 0);
154 dest
.writeLong(mLastSyncDateForProperties
);
155 dest
.writeLong(mLastSyncDateForData
);
156 dest
.writeString(mEtag
);
157 dest
.writeInt(mShareByLink ?
1 : 0);
158 dest
.writeString(mPublicLink
);
159 dest
.writeString(mPermissions
);
160 dest
.writeString(mRemoteId
);
161 dest
.writeInt(mNeedsUpdateThumbnail ?
1 : 0);
162 dest
.writeInt(mIsDownloading ?
1 : 0);
163 dest
.writeString(mEtagInConflict
);
164 dest
.writeInt(mShareWithSharee ?
1 : 0);
168 * Gets the ID of the file
170 * @return the file ID
172 public long getFileId() {
177 * Returns the remote path of the file on ownCloud
179 * @return The remote path to the file
181 public String
getRemotePath() {
186 * Can be used to check, whether or not this file exists in the database
189 * @return true, if the file exists in the database
191 public boolean fileExists() {
196 * Use this to find out if this file is a folder.
198 * @return true if it is a folder
200 public boolean isFolder() {
201 return mMimeType
!= null
&& mMimeType
.equals("DIR");
205 * Use this to check if this file is available locally
207 * @return true if it is
209 public boolean isDown() {
210 if (mLocalPath
!= null
&& mLocalPath
.length() > 0) {
211 File file
= new File(mLocalPath
);
212 return (file
.exists());
218 * The path, where the file is stored locally
220 * @return The local path to the file
222 public String
getStoragePath() {
227 * The URI to the file contents, if stored locally
229 * @return A URI to the local copy of the file, or NULL if not stored in the device
231 public Uri
getStorageUri() {
232 if (mLocalPath
== null
|| mLocalPath
.length() == 0) {
235 if (mLocalUri
== null
) {
236 Uri
.Builder builder
= new Uri
.Builder();
237 builder
.scheme(ContentResolver
.SCHEME_FILE
);
238 builder
.path(mLocalPath
);
239 mLocalUri
= builder
.build();
245 * Can be used to set the path where the file is stored
247 * @param storage_path to set
249 public void setStoragePath(String storage_path
) {
250 mLocalPath
= storage_path
;
255 * Get a UNIX timestamp of the file creation time
257 * @return A UNIX timestamp of the time that file was created
259 public long getCreationTimestamp() {
260 return mCreationTimestamp
;
264 * Set a UNIX timestamp of the time the file was created
266 * @param creation_timestamp to set
268 public void setCreationTimestamp(long creation_timestamp
) {
269 mCreationTimestamp
= creation_timestamp
;
273 * Get a UNIX timestamp of the file modification time.
275 * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
276 * in the last synchronization of the properties of this file.
278 public long getModificationTimestamp() {
279 return mModifiedTimestamp
;
283 * Set a UNIX timestamp of the time the time the file was modified.
285 * To update with the value returned by the server in every synchronization of the properties
288 * @param modification_timestamp to set
290 public void setModificationTimestamp(long modification_timestamp
) {
291 mModifiedTimestamp
= modification_timestamp
;
296 * Get a UNIX timestamp of the file modification time.
298 * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
299 * in the last synchronization of THE CONTENTS of this file.
301 public long getModificationTimestampAtLastSyncForData() {
302 return mModifiedTimestampAtLastSyncForData
;
306 * Set a UNIX timestamp of the time the time the file was modified.
308 * To update with the value returned by the server in every synchronization of THE CONTENTS
311 * @param modificationTimestamp to set
313 public void setModificationTimestampAtLastSyncForData(long modificationTimestamp
) {
314 mModifiedTimestampAtLastSyncForData
= modificationTimestamp
;
319 * Returns the filename and "/" for the root directory
321 * @return The name of the file
323 public String
getFileName() {
324 File f
= new File(getRemotePath());
325 return f
.getName().length() == 0 ? ROOT_PATH
: f
.getName();
329 * Sets the name of the file
331 * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root
334 public void setFileName(String name
) {
335 Log_OC
.d(TAG
, "OCFile name changin from " + mRemotePath
);
336 if (name
!= null
&& name
.length() > 0 && !name
.contains(PATH_SEPARATOR
) &&
337 !mRemotePath
.equals(ROOT_PATH
)) {
338 String parent
= (new File(getRemotePath())).getParent();
339 parent
= (parent
.endsWith(PATH_SEPARATOR
)) ? parent
: parent
+ PATH_SEPARATOR
;
340 mRemotePath
= parent
+ name
;
342 mRemotePath
+= PATH_SEPARATOR
;
344 Log_OC
.d(TAG
, "OCFile name changed to " + mRemotePath
);
349 * Can be used to get the Mimetype
351 * @return the Mimetype as a String
353 public String
getMimetype() {
358 * Used internally. Reset all file properties
360 private void resetData() {
367 mCreationTimestamp
= 0;
368 mModifiedTimestamp
= 0;
369 mModifiedTimestampAtLastSyncForData
= 0;
370 mLastSyncDateForProperties
= 0;
371 mLastSyncDateForData
= 0;
373 mNeedsUpdating
= false
;
375 mShareByLink
= false
;
379 mNeedsUpdateThumbnail
= false
;
380 mIsDownloading
= false
;
381 mEtagInConflict
= null
;
382 mShareWithSharee
= false
;
386 * Sets the ID of the file
388 * @param file_id to set
390 public void setFileId(long file_id
) {
395 * Sets the Mime-Type of the
397 * @param mimetype to set
399 public void setMimetype(String mimetype
) {
400 mMimeType
= mimetype
;
404 * Sets the ID of the parent folder
406 * @param parent_id to set
408 public void setParentId(long parent_id
) {
409 mParentId
= parent_id
;
413 * Sets the file size in bytes
415 * @param file_len to set
417 public void setFileLength(long file_len
) {
422 * Returns the size of the file in bytes
424 * @return The filesize in bytes
426 public long getFileLength() {
431 * Returns the ID of the parent Folder
435 public long getParentId() {
440 * Check, if this file needs updating
444 public boolean needsUpdatingWhileSaving() {
445 return mNeedsUpdating
;
448 public boolean needsUpdateThumbnail() {
449 return mNeedsUpdateThumbnail
;
452 public void setNeedsUpdateThumbnail(boolean needsUpdateThumbnail
) {
453 this.mNeedsUpdateThumbnail
= needsUpdateThumbnail
;
456 public long getLastSyncDateForProperties() {
457 return mLastSyncDateForProperties
;
460 public void setLastSyncDateForProperties(long lastSyncDate
) {
461 mLastSyncDateForProperties
= lastSyncDate
;
464 public long getLastSyncDateForData() {
465 return mLastSyncDateForData
;
468 public void setLastSyncDateForData(long lastSyncDate
) {
469 mLastSyncDateForData
= lastSyncDate
;
472 public void setFavorite(boolean favorite
) {
473 mFavorite
= favorite
;
476 public boolean isFavorite() {
481 public int describeContents() {
482 return super.hashCode();
486 public int compareTo(OCFile another
) {
487 if (isFolder() && another
.isFolder()) {
488 return getRemotePath().toLowerCase().compareTo(another
.getRemotePath().toLowerCase());
489 } else if (isFolder()) {
491 } else if (another
.isFolder()) {
494 return new AlphanumComparator().compare(this, another
);
498 public boolean equals(Object o
) {
499 if (o
instanceof OCFile
) {
500 OCFile that
= (OCFile
) o
;
502 return this.mId
== that
.mId
;
510 public String
toString() {
511 String asString
= "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " +
512 "parentId=%s, favorite=%s etag=%s]";
513 asString
= String
.format(asString
, Long
.valueOf(mId
), getFileName(), mMimeType
, isDown(),
514 mLocalPath
, mRemotePath
, Long
.valueOf(mParentId
), Boolean
.valueOf(mFavorite
),
519 public String
getEtag() {
523 public void setEtag(String etag
) {
524 this.mEtag
= (etag
!= null ? etag
: "");
528 public boolean isSharedViaLink() {
532 public void setShareViaLink(boolean shareByLink
) {
533 this.mShareByLink
= shareByLink
;
536 public String
getPublicLink() {
540 public void setPublicLink(String publicLink
) {
541 this.mPublicLink
= publicLink
;
544 public long getLocalModificationTimestamp() {
545 if (mLocalPath
!= null
&& mLocalPath
.length() > 0) {
546 File f
= new File(mLocalPath
);
547 return f
.lastModified();
553 * @return 'True' if the file contains audio
555 public boolean isAudio() {
556 return (mMimeType
!= null
&& mMimeType
.startsWith("audio/"));
560 * @return 'True' if the file contains video
562 public boolean isVideo() {
563 return (mMimeType
!= null
&& mMimeType
.startsWith("video/"));
567 * @return 'True' if the file contains an image
569 public boolean isImage() {
570 return ((mMimeType
!= null
&& mMimeType
.startsWith("image/")) ||
571 getMimeTypeFromName().startsWith("image/"));
575 * @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx)
577 public boolean isText() {
578 return ((mMimeType
!= null
&& mMimeType
.startsWith("text/")) ||
579 getMimeTypeFromName().startsWith("text/"));
582 public String
getMimeTypeFromName() {
583 String extension
= "";
584 int pos
= mRemotePath
.lastIndexOf('.');
586 extension
= mRemotePath
.substring(pos
+ 1);
588 String result
= MimeTypeMap
.getSingleton().
589 getMimeTypeFromExtension(extension
.toLowerCase());
590 return (result
!= null
) ? result
: "";
594 * @return 'True' if the file is hidden
596 public boolean isHidden() {
597 return getFileName().startsWith(".");
600 public String
getPermissions() {
604 public void setPermissions(String permissions
) {
605 this.mPermissions
= permissions
;
608 public String
getRemoteId() {
612 public void setRemoteId(String remoteId
) {
613 this.mRemoteId
= remoteId
;
616 public boolean isDownloading() {
617 return mIsDownloading
;
620 public void setDownloading(boolean isDownloading
) {
621 this.mIsDownloading
= isDownloading
;
624 public String
getEtagInConflict() {
625 return mEtagInConflict
;
628 public void setEtagInConflict(String etagInConflict
) {
629 mEtagInConflict
= etagInConflict
;
632 public boolean isSharedWithSharee() {
633 return mShareWithSharee
;
636 public void setShareWithSharee(boolean shareWithSharee
) {
637 this.mShareWithSharee
= shareWithSharee
;
640 public boolean isSharedWithMe() {
641 String permissions
= getPermissions();
642 return (permissions
!= null
&& permissions
.contains(PERMISSION_SHARED_WITH_ME
));