package com.orgzly.android.repos;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.support.v4.provider.DocumentFile;
import android.util.Log;
import com.orgzly.BuildConfig;
import com.orgzly.android.BookName;
import com.orgzly.android.util.LogUtils;
import com.orgzly.android.util.MiscUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Using DocumentFile, for devices running Lollipop or later.
*/
public class ContentRepo implements Repo {
private static final String TAG = ContentRepo.class.getName();
public static final String SCHEME = "content";
private final Context context;
private final Uri repoUri;
private final DocumentFile repoDocumentFile;
public ContentRepo(Context context, Uri uri) throws IOException {
this.context = context;
this.repoUri = uri;
this.repoDocumentFile = DocumentFile.fromTreeUri(context, uri);
}
@Override
public boolean requiresConnection() {
return false;
}
@Override
public Uri getUri() {
return repoUri;
}
@Override
public List<VersionedRook> getBooks() throws IOException {
List<VersionedRook> result = new ArrayList<>();
DocumentFile[] files = repoDocumentFile.listFiles();
if (files != null) {
// Can't compare TreeDocumentFile
// Arrays.sort(files);
for (int i = 0; i < files.length; i++) {
DocumentFile file = files[i];
if (BookName.isSupportedFormatFileName(file.getName())) {
if (BuildConfig.LOG_DEBUG) {
LogUtils.d(TAG,
"file.getName()", file.getName(),
"getUri()", getUri(),
"repoDocumentFile.getUri()", repoDocumentFile.getUri(),
"file", file,
"file.getUri()", file.getUri(),
"file.getParentFile()", file.getParentFile().getUri());
}
result.add(new VersionedRook(
getUri(),
file.getUri(),
String.valueOf(file.lastModified()),
file.lastModified()
));
}
}
} else {
Log.e(TAG, "Listing files in " + getUri() + " returned null.");
}
return result;
}
@Override
public VersionedRook retrieveBook(Uri uri, File destinationFile) throws IOException {
DocumentFile sourceFile = DocumentFile.fromSingleUri(context, uri);
/* "Download" the file. */
InputStream is = context.getContentResolver().openInputStream(uri);
try {
MiscUtils.writeStreamToFile(is, destinationFile);
} finally {
is.close();
}
String rev = String.valueOf(sourceFile.lastModified());
long mtime = sourceFile.lastModified();
return new VersionedRook(repoUri, uri, rev, mtime);
}
@Override
public VersionedRook storeBook(File file, String fileName) throws IOException {
if (!file.exists()) {
throw new FileNotFoundException("File " + file + " does not exist");
}
/* Delete existing file. */
DocumentFile existingFile = repoDocumentFile.findFile(fileName);
if (existingFile != null) {
existingFile.delete();
}
/* Create new file. */
DocumentFile destinationFile = repoDocumentFile.createFile("text/*", fileName);
if (destinationFile == null) {
throw new IOException("Failed creating " + fileName + " in " + repoUri);
}
Uri uri = destinationFile.getUri();
/* Write file content to uri. */
OutputStream out = context.getContentResolver().openOutputStream(uri);
try {
MiscUtils.writeFileToStream(file, out);
} finally {
if (out != null) {
out.close();
}
}
String rev = String.valueOf(destinationFile.lastModified());
long mtime = destinationFile.lastModified();
return new VersionedRook(getUri(), uri, rev, mtime);
}
@Override
public VersionedRook renameBook(Uri from, String name) throws IOException {
DocumentFile fromDocFile = DocumentFile.fromSingleUri(context, from);
BookName bookName = BookName.fromFileName(fromDocFile.getName());
String newFileName = BookName.fileName(name, bookName.getFormat());
/* Check if document already exists. */
DocumentFile existingFile = repoDocumentFile.findFile(newFileName);
if (existingFile != null) {
throw new IOException("File at " + existingFile.getUri() + " already exists");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Uri newUri = DocumentsContract.renameDocument(context.getContentResolver(), from, newFileName);
long mtime = fromDocFile.lastModified();
String rev = String.valueOf(mtime);
return new VersionedRook(getUri(), newUri, rev, mtime);
} else {
/*
* This should never happen, unless the user downgraded
* and uses the same repo uri.
*/
throw new IOException("Renaming notebooks is not supported on your device " +
"(requires at least Lollipop)");
}
}
@Override
public void delete(Uri uri) throws IOException {
DocumentFile docFile = DocumentFile.fromSingleUri(context, uri);
if (docFile != null && docFile.exists()) {
if (! docFile.delete()) {
throw new IOException("Failed deleting document " + uri);
}
}
}
@Override
public String toString() {
return getUri().toString();
}
}