* Cached after first call, until changed. */ private Uri exposedFileUri; @Getter @Setter private String encryptedFileName; /** * Create new {@link OCFile} with given path. *
* The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'. * * @param path The remote path of the file. */ public OCFile(String path) { resetData(); needsUpdatingWhileSaving = false; if (path == null || path.length() <= 0 || !path.startsWith(PATH_SEPARATOR)) { throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path); } remotePath = path; } /** * Reconstruct from parcel * * @param source The source parcel */ private OCFile(Parcel source) { fileId = source.readLong(); parentId = source.readLong(); fileLength = source.readLong(); creationTimestamp = source.readLong(); modificationTimestamp = source.readLong(); modificationTimestampAtLastSyncForData = source.readLong(); remotePath = source.readString(); localPath = source.readString(); mimeType = source.readString(); needsUpdatingWhileSaving = source.readInt() == 0; availableOffline = source.readInt() == 1; lastSyncDateForProperties = source.readLong(); lastSyncDateForData = source.readLong(); etag = source.readString(); sharedViaLink = source.readInt() == 1; publicLink = source.readString(); permissions = source.readString(); remoteId = source.readString(); updateThumbnailNeeded = source.readInt() == 1; downloading = source.readInt() == 1; etagInConflict = source.readString(); sharedWithSharee = source.readInt() == 1; favorite = source.readInt() == 1; encrypted = source.readInt() == 1; encryptedFileName = source.readString(); mountType = (WebdavEntry.MountType) source.readSerializable(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(fileId); dest.writeLong(parentId); dest.writeLong(fileLength); dest.writeLong(creationTimestamp); dest.writeLong(modificationTimestamp); dest.writeLong(modificationTimestampAtLastSyncForData); dest.writeString(remotePath); dest.writeString(localPath); dest.writeString(mimeType); dest.writeInt(needsUpdatingWhileSaving ? 1 : 0); dest.writeInt(availableOffline ? 1 : 0); dest.writeLong(lastSyncDateForProperties); dest.writeLong(lastSyncDateForData); dest.writeString(etag); dest.writeInt(sharedViaLink ? 1 : 0); dest.writeString(publicLink); dest.writeString(permissions); dest.writeString(remoteId); dest.writeInt(updateThumbnailNeeded ? 1 : 0); dest.writeInt(downloading ? 1 : 0); dest.writeString(etagInConflict); dest.writeInt(sharedWithSharee ? 1 : 0); dest.writeInt(favorite ? 1 : 0); dest.writeInt(encrypted ? 1 : 0); dest.writeString(encryptedFileName); dest.writeSerializable(mountType); } public String getDecryptedRemotePath() { return remotePath; } /** * Returns the remote path of the file on ownCloud * * @return The remote path to the file */ public String getRemotePath() { if (isEncrypted() && !isFolder()) { String parentPath = new File(remotePath).getParent(); if (parentPath.endsWith("/")) { return parentPath + getEncryptedFileName(); } else { return parentPath + "/" + getEncryptedFileName(); } } else { if (isFolder()) { if (remotePath.endsWith("/")) { return remotePath; } else { return remotePath + "/"; } } else { return remotePath; } } } /** * Can be used to check, whether or not this file exists in the database * already * * @return true, if the file exists in the database */ public boolean fileExists() { return fileId != -1; } /** * Use this to find out if this file is a folder. * * @return true if it is a folder */ public boolean isFolder() { return MimeType.DIRECTORY.equals(mimeType); } /** * Sets mimetype to folder and returns this file * Only for testing * * @return OCFile this file */ public OCFile setFolder() { setMimeType(MimeType.DIRECTORY); return this; } /** * Use this to check if this file is available locally * * @return true if it is */ public boolean isDown() { return !isFolder() && existsOnDevice(); } /** * Use this to check if this file or folder is available locally * * @return true if it is */ public boolean existsOnDevice() { if (localPath != null && localPath.length() > 0) { return new File(localPath).exists(); } return false; } /** * The path, where the file is stored locally * * @return The local path to the file */ public String getStoragePath() { return localPath; } /** * The URI to the file contents, if stored locally * * @return A URI to the local copy of the file, or NULL if not stored in the device */ public Uri getStorageUri() { if (localPath == null || localPath.length() == 0) { return null; } if (localUri == null) { Uri.Builder builder = new Uri.Builder(); builder.scheme(ContentResolver.SCHEME_FILE); builder.path(localPath); localUri = builder.build(); } return localUri; } public Uri getLegacyExposedFileUri() { if (localPath == null || localPath.length() == 0) { return null; } if (exposedFileUri == null) { return Uri.parse(ContentResolver.SCHEME_FILE + "://" + WebdavUtils.encodePath(localPath)); } return exposedFileUri; } /* Partly disabled because not all apps understand paths that we get via this method for now */ public Uri getExposedFileUri(Context context) { if (localPath == null || localPath.length() == 0) { return null; } if (exposedFileUri == null) { try { exposedFileUri = FileProvider.getUriForFile( context, context.getString(R.string.file_provider_authority), new File(localPath)); } catch (IllegalArgumentException ex) { // Could not share file using FileProvider URI scheme. // Fall back to legacy URI parsing. getLegacyExposedFileUri(); } } return exposedFileUri; } /** * Can be used to set the path where the file is stored * * @param storage_path to set */ public void setStoragePath(String storage_path) { localPath = storage_path; localUri = null; exposedFileUri = null; } /** * Returns the filename and "/" for the root directory * * @return The name of the file */ public String getFileName() { File f = new File(remotePath); return f.getName().length() == 0 ? ROOT_PATH : f.getName(); } /** * Sets the name of the file *
* Does nothing if the new name is null, empty or includes "/" ; or if the file is the root * directory */ public void setFileName(String name) { Log_OC.d(TAG, "OCFile name changing from " + remotePath); if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !ROOT_PATH.equals(remotePath)) { String parent = new File(this.getRemotePath()).getParent(); parent = parent.endsWith(PATH_SEPARATOR) ? parent : parent + PATH_SEPARATOR; remotePath = parent + name; if (isFolder()) { remotePath += PATH_SEPARATOR; } Log_OC.d(TAG, "OCFile name changed to " + remotePath); } } /** * Used internally. Reset all file properties */ private void resetData() { fileId = -1; remotePath = null; parentId = 0; localPath = null; mimeType = null; fileLength = 0; creationTimestamp = 0; modificationTimestamp = 0; modificationTimestampAtLastSyncForData = 0; lastSyncDateForProperties = 0; lastSyncDateForData = 0; availableOffline = false; needsUpdatingWhileSaving = false; etag = null; sharedViaLink = false; publicLink = null; permissions = null; remoteId = null; updateThumbnailNeeded = false; downloading = false; etagInConflict = null; sharedWithSharee = false; favorite = false; encrypted = false; encryptedFileName = null; mountType = WebdavEntry.MountType.INTERNAL; } /** * get remote path of parent file * * @return remote path */ public String getParentRemotePath() { String parentPath = new File(this.getRemotePath()).getParent(); return parentPath.endsWith("/") ? parentPath : parentPath + "/"; } @Override public int describeContents() { return super.hashCode(); } @Override public int compareTo(@NonNull OCFile another) { if (isFolder() && another.isFolder()) { return new AlphanumComparator().compare(this, another); } else if (isFolder()) { return -1; } else if (another.isFolder()) { return 1; } return new AlphanumComparator().compare(this, another); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } OCFile ocFile = (OCFile) o; return fileId == ocFile.fileId && parentId == ocFile.parentId; } @Override public int hashCode() { return 31 * (int) (fileId ^ (fileId >>> 32)) + (int) (parentId ^ (parentId >>> 32)); } @NonNull @Override public String toString() { String asString = "[fileId=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " + "parentId=%s, availableOffline=%s etag=%s favourite=%s]"; return String.format(asString, fileId, getFileName(), mimeType, isDown(), localPath, remotePath, parentId, availableOffline, etag, favorite); } public void setEtag(String etag) { this.etag = etag != null ? etag : ""; } public long getLocalModificationTimestamp() { if (localPath != null && localPath.length() > 0) { File f = new File(localPath); return f.lastModified(); } return 0; } /** * @return 'True' if the file is hidden */ public boolean isHidden() { return getFileName().length() > 0 && getFileName().charAt(0) == '.'; } /** * The unique fileId for the file within the instance * * @return file fileId, unique within the instance */ public String getLocalId() { return getRemoteId().substring(0, 8).replaceAll("^0*", ""); } public boolean isInConflict() { return etagInConflict != null && !"".equals(etagInConflict); } public boolean isSharedWithMe() { String permissions = getPermissions(); return permissions != null && permissions.contains(PERMISSION_SHARED_WITH_ME); } public boolean canReshare() { String permissions = getPermissions(); return permissions != null && permissions.contains(PERMISSION_CAN_RESHARE); } public boolean canWrite() { String permissions = getPermissions(); return permissions != null && permissions.contains(PERMISSION_CAN_WRITE); } public static final Parcelable.Creator