2  *   ownCloud Android client application 
   4  *   Copyright (C) 2012  Bartek Przybylski 
   5  *   Copyright (C) 2015 ownCloud Inc. 
   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. 
  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. 
  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/>. 
  21 package com
.owncloud
.android
.datamodel
; 
  23 import android
.os
.Parcel
; 
  24 import android
.os
.Parcelable
; 
  25 import android
.webkit
.MimeTypeMap
; 
  27 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
; 
  30 import java
.io
.Serializable
; 
  32 import third_parties
.daveKoeller
.AlphanumComparator
; 
  33 public class OCFile 
implements Parcelable
, Comparable
<OCFile
> { 
  35     public static final Parcelable
.Creator CREATOR 
= new Parcelable
.Creator() { 
  36         public OCFile 
createFromParcel(Parcel source
) { 
  37             return new OCFile(source
); 
  40         public OCFile
[] newArray(int size
) { 
  41             return new OCFile
[size
]; 
  45     public static final String PATH_SEPARATOR 
= "/"; 
  46     public static final String ROOT_PATH 
= PATH_SEPARATOR
; 
  48     private static final String TAG 
= OCFile
.class.getSimpleName(); 
  51     private long mParentId
; 
  53     private long mCreationTimestamp
; 
  54     private long mModifiedTimestamp
; 
  55     private long mModifiedTimestampAtLastSyncForData
; 
  56     private String mRemotePath
; 
  57     private String mLocalPath
; 
  58     private String mMimeType
; 
  59     private boolean mNeedsUpdating
; 
  60     private long mLastSyncDateForProperties
; 
  61     private long mLastSyncDateForData
; 
  62     private boolean mFavorite
; 
  66     private boolean mShareByLink
; 
  67     private String mPublicLink
; 
  69     private String mPermissions
; 
  70     private String mRemoteId
; 
  72     private boolean mNeedsUpdateThumbnail
; 
  74     private boolean mIsDownloading
; 
  78      * Create new {@link OCFile} with given path. 
  80      * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'. 
  82      * @param path The remote path of the file. 
  84     public OCFile(String path
) { 
  86         mNeedsUpdating 
= false
; 
  87         if (path 
== null 
|| path
.length() <= 0 || !path
.startsWith(PATH_SEPARATOR
)) { 
  88             throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path
); 
  94      * Reconstruct from parcel 
  96      * @param source The source parcel 
  98     private OCFile(Parcel source
) { 
  99         mId 
= source
.readLong(); 
 100         mParentId 
= source
.readLong(); 
 101         mLength 
= source
.readLong(); 
 102         mCreationTimestamp 
= source
.readLong(); 
 103         mModifiedTimestamp 
= source
.readLong(); 
 104         mModifiedTimestampAtLastSyncForData 
= source
.readLong(); 
 105         mRemotePath 
= source
.readString(); 
 106         mLocalPath 
= source
.readString(); 
 107         mMimeType 
= source
.readString(); 
 108         mNeedsUpdating 
= source
.readInt() == 0; 
 109         mFavorite 
= source
.readInt() == 1; 
 110         mLastSyncDateForProperties 
= source
.readLong(); 
 111         mLastSyncDateForData 
= source
.readLong(); 
 112         mEtag 
= source
.readString(); 
 113         mShareByLink 
= source
.readInt() == 1; 
 114         mPublicLink 
= source
.readString(); 
 115         mPermissions 
= source
.readString(); 
 116         mRemoteId 
= source
.readString(); 
 117         mNeedsUpdateThumbnail 
= source
.readInt() == 0; 
 118         mIsDownloading 
= source
.readInt() == 0; 
 123     public void writeToParcel(Parcel dest
, int flags
) { 
 125         dest
.writeLong(mParentId
); 
 126         dest
.writeLong(mLength
); 
 127         dest
.writeLong(mCreationTimestamp
); 
 128         dest
.writeLong(mModifiedTimestamp
); 
 129         dest
.writeLong(mModifiedTimestampAtLastSyncForData
); 
 130         dest
.writeString(mRemotePath
); 
 131         dest
.writeString(mLocalPath
); 
 132         dest
.writeString(mMimeType
); 
 133         dest
.writeInt(mNeedsUpdating ? 
1 : 0); 
 134         dest
.writeInt(mFavorite ? 
1 : 0); 
 135         dest
.writeLong(mLastSyncDateForProperties
); 
 136         dest
.writeLong(mLastSyncDateForData
); 
 137         dest
.writeString(mEtag
); 
 138         dest
.writeInt(mShareByLink ? 
1 : 0); 
 139         dest
.writeString(mPublicLink
); 
 140         dest
.writeString(mPermissions
); 
 141         dest
.writeString(mRemoteId
); 
 142         dest
.writeInt(mNeedsUpdateThumbnail ? 
1 : 0); 
 143         dest
.writeInt(mIsDownloading ? 
1 : 0); 
 147      * Gets the ID of the file 
 149      * @return the file ID 
 151     public long getFileId() { 
 156      * Returns the remote path of the file on ownCloud 
 158      * @return The remote path to the file 
 160     public String 
getRemotePath() { 
 165      * Can be used to check, whether or not this file exists in the database 
 168      * @return true, if the file exists in the database 
 170     public boolean fileExists() { 
 175      * Use this to find out if this file is a folder. 
 177      * @return true if it is a folder 
 179     public boolean isFolder() { 
 180         return mMimeType 
!= null 
&& mMimeType
.equals("DIR"); 
 184      * Use this to check if this file is available locally 
 186      * @return true if it is 
 188     public boolean isDown() { 
 189         if (mLocalPath 
!= null 
&& mLocalPath
.length() > 0) { 
 190             File file 
= new File(mLocalPath
); 
 191             return (file
.exists()); 
 197      * The path, where the file is stored locally 
 199      * @return The local path to the file 
 201     public String 
getStoragePath() { 
 206      * Can be used to set the path where the file is stored 
 208      * @param storage_path to set 
 210     public void setStoragePath(String storage_path
) { 
 211         mLocalPath 
= storage_path
; 
 215      * Get a UNIX timestamp of the file creation time 
 217      * @return A UNIX timestamp of the time that file was created 
 219     public long getCreationTimestamp() { 
 220         return mCreationTimestamp
; 
 224      * Set a UNIX timestamp of the time the file was created 
 226      * @param creation_timestamp to set 
 228     public void setCreationTimestamp(long creation_timestamp
) { 
 229         mCreationTimestamp 
= creation_timestamp
; 
 233      * Get a UNIX timestamp of the file modification time. 
 235      * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server 
 236      * in the last synchronization of the properties of this file. 
 238     public long getModificationTimestamp() { 
 239         return mModifiedTimestamp
; 
 243      * Set a UNIX timestamp of the time the time the file was modified. 
 245      * To update with the value returned by the server in every synchronization of the properties 
 248      * @param modification_timestamp to set 
 250     public void setModificationTimestamp(long modification_timestamp
) { 
 251         mModifiedTimestamp 
= modification_timestamp
; 
 256      * Get a UNIX timestamp of the file modification time. 
 258      * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server 
 259      * in the last synchronization of THE CONTENTS of this file. 
 261     public long getModificationTimestampAtLastSyncForData() { 
 262         return mModifiedTimestampAtLastSyncForData
; 
 266      * Set a UNIX timestamp of the time the time the file was modified. 
 268      * To update with the value returned by the server in every synchronization of THE CONTENTS 
 271      * @param modificationTimestamp to set 
 273     public void setModificationTimestampAtLastSyncForData(long modificationTimestamp
) { 
 274         mModifiedTimestampAtLastSyncForData 
= modificationTimestamp
; 
 279      * Returns the filename and "/" for the root directory 
 281      * @return The name of the file 
 283     public String 
getFileName() { 
 284         File f 
= new File(getRemotePath()); 
 285         return f
.getName().length() == 0 ? ROOT_PATH 
: f
.getName(); 
 289      * Sets the name of the file 
 291      * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root 
 294     public void setFileName(String name
) { 
 295         Log_OC
.d(TAG
, "OCFile name changin from " + mRemotePath
); 
 296         if (name 
!= null 
&& name
.length() > 0 && !name
.contains(PATH_SEPARATOR
) && 
 297                 !mRemotePath
.equals(ROOT_PATH
)) { 
 298             String parent 
= (new File(getRemotePath())).getParent(); 
 299             parent 
= (parent
.endsWith(PATH_SEPARATOR
)) ? parent 
: parent 
+ PATH_SEPARATOR
; 
 300             mRemotePath 
= parent 
+ name
; 
 302                 mRemotePath 
+= PATH_SEPARATOR
; 
 304             Log_OC
.d(TAG
, "OCFile name changed to " + mRemotePath
); 
 309      * Can be used to get the Mimetype 
 311      * @return the Mimetype as a String 
 313     public String 
getMimetype() { 
 318      * Adds a file to this directory. If this file is not a directory, an 
 319      * exception gets thrown. 
 322      * @throws IllegalStateException if you try to add a something and this is 
 325     public void addFile(OCFile file
) throws IllegalStateException 
{ 
 327             file
.mParentId 
= mId
; 
 328             mNeedsUpdating 
= true
; 
 331         throw new IllegalStateException( 
 332                 "This is not a directory where you can add stuff to!"); 
 336      * Used internally. Reset all file properties 
 338     private void resetData() { 
 345         mCreationTimestamp 
= 0; 
 346         mModifiedTimestamp 
= 0; 
 347         mModifiedTimestampAtLastSyncForData 
= 0; 
 348         mLastSyncDateForProperties 
= 0; 
 349         mLastSyncDateForData 
= 0; 
 351         mNeedsUpdating 
= false
; 
 353         mShareByLink 
= false
; 
 357         mNeedsUpdateThumbnail 
= false
; 
 358         mIsDownloading 
= false
; 
 362      * Sets the ID of the file 
 364      * @param file_id to set 
 366     public void setFileId(long file_id
) { 
 371      * Sets the Mime-Type of the 
 373      * @param mimetype to set 
 375     public void setMimetype(String mimetype
) { 
 376         mMimeType 
= mimetype
; 
 380      * Sets the ID of the parent folder 
 382      * @param parent_id to set 
 384     public void setParentId(long parent_id
) { 
 385         mParentId 
= parent_id
; 
 389      * Sets the file size in bytes 
 391      * @param file_len to set 
 393     public void setFileLength(long file_len
) { 
 398      * Returns the size of the file in bytes 
 400      * @return The filesize in bytes 
 402     public long getFileLength() { 
 407      * Returns the ID of the parent Folder 
 411     public long getParentId() { 
 416      * Check, if this file needs updating 
 420     public boolean needsUpdatingWhileSaving() { 
 421         return mNeedsUpdating
; 
 424     public boolean needsUpdateThumbnail() { 
 425         return mNeedsUpdateThumbnail
; 
 428     public void setNeedsUpdateThumbnail(boolean needsUpdateThumbnail
) { 
 429         this.mNeedsUpdateThumbnail 
= needsUpdateThumbnail
; 
 432     public long getLastSyncDateForProperties() { 
 433         return mLastSyncDateForProperties
; 
 436     public void setLastSyncDateForProperties(long lastSyncDate
) { 
 437         mLastSyncDateForProperties 
= lastSyncDate
; 
 440     public long getLastSyncDateForData() { 
 441         return mLastSyncDateForData
; 
 444     public void setLastSyncDateForData(long lastSyncDate
) { 
 445         mLastSyncDateForData 
= lastSyncDate
; 
 448     public void setFavorite(boolean favorite
) { 
 449         mFavorite 
= favorite
; 
 452     public boolean isFavorite() { 
 457     public int describeContents() { 
 458         return super.hashCode(); 
 462     public int compareTo(OCFile another
) { 
 463         if (isFolder() && another
.isFolder()) { 
 464             return getRemotePath().toLowerCase().compareTo(another
.getRemotePath().toLowerCase()); 
 465         } else if (isFolder()) { 
 467         } else if (another
.isFolder()) { 
 470         return new AlphanumComparator().compare(this, another
); 
 474     public boolean equals(Object o
) { 
 475         if (o 
instanceof OCFile
) { 
 476             OCFile that 
= (OCFile
) o
; 
 478                 return this.mId 
== that
.mId
; 
 486     public String 
toString() { 
 487         String asString 
= "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " + 
 488                 "parentId=%s, favorite=%s etag=%s]"; 
 489         asString 
= String
.format(asString
, Long
.valueOf(mId
), getFileName(), mMimeType
, isDown(), 
 490                 mLocalPath
, mRemotePath
, Long
.valueOf(mParentId
), Boolean
.valueOf(mFavorite
), 
 495     public String 
getEtag() { 
 499     public void setEtag(String etag
) { 
 504     public boolean isShareByLink() { 
 508     public void setShareByLink(boolean shareByLink
) { 
 509         this.mShareByLink 
= shareByLink
; 
 512     public String 
getPublicLink() { 
 516     public void setPublicLink(String publicLink
) { 
 517         this.mPublicLink 
= publicLink
; 
 520     public long getLocalModificationTimestamp() { 
 521         if (mLocalPath 
!= null 
&& mLocalPath
.length() > 0) { 
 522             File f 
= new File(mLocalPath
); 
 523             return f
.lastModified(); 
 529      * @return 'True' if the file contains audio 
 531     public boolean isAudio() { 
 532         return (mMimeType 
!= null 
&& mMimeType
.startsWith("audio/")); 
 536      * @return 'True' if the file contains video 
 538     public boolean isVideo() { 
 539         return (mMimeType 
!= null 
&& mMimeType
.startsWith("video/")); 
 543      * @return 'True' if the file contains an image 
 545     public boolean isImage() { 
 546         return ((mMimeType 
!= null 
&& mMimeType
.startsWith("image/")) || 
 547                 getMimeTypeFromName().startsWith("image/")); 
 551      * @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx) 
 553     public boolean isText() { 
 554         return ((mMimeType 
!= null 
&& mMimeType
.startsWith("text/")) || 
 555                 getMimeTypeFromName().startsWith("text/")); 
 558     public String 
getMimeTypeFromName() { 
 559         String extension 
= ""; 
 560         int pos 
= mRemotePath
.lastIndexOf('.'); 
 562             extension 
= mRemotePath
.substring(pos 
+ 1); 
 564         String result 
= MimeTypeMap
.getSingleton(). 
 565                 getMimeTypeFromExtension(extension
.toLowerCase()); 
 566         return (result 
!= null
) ? result 
: ""; 
 570      * @return 'True' if the file is hidden 
 572     public boolean isHidden() { 
 573         return getFileName().startsWith("."); 
 576     public String 
getPermissions() { 
 580     public void setPermissions(String permissions
) { 
 581         this.mPermissions 
= permissions
; 
 584     public String 
getRemoteId() { 
 588     public void setRemoteId(String remoteId
) { 
 589         this.mRemoteId 
= remoteId
; 
 592     public boolean isDownloading() { 
 593         return mIsDownloading
; 
 596     public void setDownloading(boolean isDownloading
) { 
 597         this.mIsDownloading 
= isDownloading
; 
 600     public boolean isSynchronizing() { 
 601         // TODO real implementation