Use Path in the download helper classes.
This commit is contained in:
parent
2cb973f150
commit
6df808f266
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -14,21 +15,27 @@ import androidx.documentfile.provider.DocumentFile;
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME;
|
import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME;
|
||||||
import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID;
|
import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
public class StoredDirectoryHelper {
|
public class StoredDirectoryHelper {
|
||||||
|
private static final String TAG = StoredDirectoryHelper.class.getSimpleName();
|
||||||
public static final int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
public static final int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||||
|
|
||||||
private File ioTree;
|
private Path ioTree;
|
||||||
private DocumentFile docTree;
|
private DocumentFile docTree;
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
|
@ -40,7 +47,7 @@ public class StoredDirectoryHelper {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
|
||||||
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(path.getScheme())) {
|
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(path.getScheme())) {
|
||||||
this.ioTree = new File(URI.create(path.toString()));
|
ioTree = Paths.get(URI.create(path.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,13 +71,17 @@ public class StoredDirectoryHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoredFileHelper createUniqueFile(final String name, final String mime) {
|
public StoredFileHelper createUniqueFile(final String name, final String mime) {
|
||||||
final ArrayList<String> matches = new ArrayList<>();
|
final List<String> matches = new ArrayList<>();
|
||||||
final String[] filename = splitFilename(name);
|
final String[] filename = splitFilename(name);
|
||||||
final String lcFilename = filename[0].toLowerCase();
|
final String lcFileName = filename[0].toLowerCase();
|
||||||
|
|
||||||
if (docTree == null) {
|
if (docTree == null) {
|
||||||
for (final File file : ioTree.listFiles()) {
|
try (Stream<Path> stream = Files.list(ioTree)) {
|
||||||
addIfStartWith(matches, lcFilename, file.getName());
|
matches.addAll(stream.map(path -> path.getFileName().toString().toLowerCase())
|
||||||
|
.filter(fileName -> fileName.startsWith(lcFileName))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
} catch (final IOException e) {
|
||||||
|
Log.e(TAG, "Exception while traversing " + ioTree, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// warning: SAF file listing is very slow
|
// warning: SAF file listing is very slow
|
||||||
|
@ -82,10 +93,10 @@ public class StoredDirectoryHelper {
|
||||||
final ContentResolver cr = context.getContentResolver();
|
final ContentResolver cr = context.getContentResolver();
|
||||||
|
|
||||||
try (Cursor cursor = cr.query(docTreeChildren, projection, selection,
|
try (Cursor cursor = cr.query(docTreeChildren, projection, selection,
|
||||||
new String[]{lcFilename}, null)) {
|
new String[]{lcFileName}, null)) {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
addIfStartWith(matches, lcFilename, cursor.getString(0));
|
addIfStartWith(matches, lcFileName, cursor.getString(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +123,7 @@ public class StoredDirectoryHelper {
|
||||||
Collections.sort(matches, String::compareTo);
|
Collections.sort(matches, String::compareTo);
|
||||||
|
|
||||||
for (int i = 1; i < 1000; i++) {
|
for (int i = 1; i < 1000; i++) {
|
||||||
if (Collections.binarySearch(matches, makeFileName(lcFilename, i, filename[1])) < 0) {
|
if (Collections.binarySearch(matches, makeFileName(lcFileName, i, filename[1])) < 0) {
|
||||||
return createFile(makeFileName(filename[0], i, filename[1]), mime, true);
|
return createFile(makeFileName(filename[0], i, filename[1]), mime, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,11 +152,11 @@ public class StoredDirectoryHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getUri() {
|
public Uri getUri() {
|
||||||
return docTree == null ? Uri.fromFile(ioTree) : docTree.getUri();
|
return docTree == null ? Uri.fromFile(ioTree.toFile()) : docTree.getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean exists() {
|
public boolean exists() {
|
||||||
return docTree == null ? ioTree.exists() : docTree.exists();
|
return docTree == null ? Files.exists(ioTree) : docTree.exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +180,9 @@ public class StoredDirectoryHelper {
|
||||||
*/
|
*/
|
||||||
public boolean mkdirs() {
|
public boolean mkdirs() {
|
||||||
if (docTree == null) {
|
if (docTree == null) {
|
||||||
return ioTree.exists() || ioTree.mkdirs();
|
// TODO: Use Files.createDirectories() when AGP 8.1 is available:
|
||||||
|
// https://issuetracker.google.com/issues/282544786
|
||||||
|
return Files.exists(ioTree) || ioTree.toFile().mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (docTree.exists()) {
|
if (docTree.exists()) {
|
||||||
|
@ -206,8 +219,8 @@ public class StoredDirectoryHelper {
|
||||||
|
|
||||||
public Uri findFile(final String filename) {
|
public Uri findFile(final String filename) {
|
||||||
if (docTree == null) {
|
if (docTree == null) {
|
||||||
final File res = new File(ioTree, filename);
|
final Path res = ioTree.resolve(filename);
|
||||||
return res.exists() ? Uri.fromFile(res) : null;
|
return Files.exists(res) ? Uri.fromFile(res.toFile()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final DocumentFile res = findFileSAFHelper(context, docTree, filename);
|
final DocumentFile res = findFileSAFHelper(context, docTree, filename);
|
||||||
|
@ -215,7 +228,7 @@ public class StoredDirectoryHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canWrite() {
|
public boolean canWrite() {
|
||||||
return docTree == null ? ioTree.canWrite() : docTree.canWrite();
|
return docTree == null ? Files.isWritable(ioTree) : docTree.canWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,14 +243,14 @@ public class StoredDirectoryHelper {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return (docTree == null ? Uri.fromFile(ioTree) : docTree.getUri()).toString();
|
return (docTree == null ? Uri.fromFile(ioTree.toFile()) : docTree.getUri()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
// Utils
|
// Utils
|
||||||
///////////////////
|
///////////////////
|
||||||
|
|
||||||
private static void addIfStartWith(final ArrayList<String> list, @NonNull final String base,
|
private static void addIfStartWith(final List<String> list, @NonNull final String base,
|
||||||
final String str) {
|
final String str) {
|
||||||
if (isNullOrEmpty(str)) {
|
if (isNullOrEmpty(str)) {
|
||||||
return;
|
return;
|
||||||
|
@ -259,7 +272,7 @@ public class StoredDirectoryHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String makeFileName(final String name, final int idx, final String ext) {
|
private static String makeFileName(final String name, final int idx, final String ext) {
|
||||||
return name.concat(" (").concat(String.valueOf(idx)).concat(")").concat(ext);
|
return name + "(" + idx + ")" + ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,6 +23,9 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import us.shandian.giga.io.FileStream;
|
import us.shandian.giga.io.FileStream;
|
||||||
import us.shandian.giga.io.FileStreamSAF;
|
import us.shandian.giga.io.FileStreamSAF;
|
||||||
|
@ -36,7 +39,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
|
|
||||||
private transient DocumentFile docFile;
|
private transient DocumentFile docFile;
|
||||||
private transient DocumentFile docTree;
|
private transient DocumentFile docTree;
|
||||||
private transient File ioFile;
|
private transient Path ioPath;
|
||||||
private transient Context context;
|
private transient Context context;
|
||||||
|
|
||||||
protected String source;
|
protected String source;
|
||||||
|
@ -49,7 +52,8 @@ public class StoredFileHelper implements Serializable {
|
||||||
|
|
||||||
public StoredFileHelper(final Context context, final Uri uri, final String mime) {
|
public StoredFileHelper(final Context context, final Uri uri, final String mime) {
|
||||||
if (FilePickerActivityHelper.isOwnFileUri(context, uri)) {
|
if (FilePickerActivityHelper.isOwnFileUri(context, uri)) {
|
||||||
ioFile = Utils.getFileForUri(uri);
|
final File ioFile = Utils.getFileForUri(uri);
|
||||||
|
ioPath = ioFile.toPath();
|
||||||
source = Uri.fromFile(ioFile).toString();
|
source = Uri.fromFile(ioFile).toString();
|
||||||
} else {
|
} else {
|
||||||
docFile = DocumentFile.fromSingleUri(context, uri);
|
docFile = DocumentFile.fromSingleUri(context, uri);
|
||||||
|
@ -100,26 +104,18 @@ public class StoredFileHelper implements Serializable {
|
||||||
this.srcType = this.docFile.getType();
|
this.srcType = this.docFile.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredFileHelper(final File location, final String filename, final String mime)
|
StoredFileHelper(final Path location, final String filename, final String mime)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this.ioFile = new File(location, filename);
|
ioPath = location.resolve(filename);
|
||||||
|
|
||||||
if (this.ioFile.exists()) {
|
Files.deleteIfExists(ioPath);
|
||||||
if (!this.ioFile.isFile() && !this.ioFile.delete()) {
|
Files.createFile(ioPath);
|
||||||
throw new IOException("The filename is already in use by non-file entity "
|
|
||||||
+ "and cannot overwrite it");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!this.ioFile.createNewFile()) {
|
|
||||||
throw new IOException("Cannot create the file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.source = Uri.fromFile(this.ioFile).toString();
|
source = Uri.fromFile(ioPath.toFile()).toString();
|
||||||
this.sourceTree = Uri.fromFile(location).toString();
|
sourceTree = Uri.fromFile(location.toFile()).toString();
|
||||||
|
|
||||||
this.srcName = ioFile.getName();
|
srcName = ioPath.getFileName().toString();
|
||||||
this.srcType = mime;
|
srcType = mime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoredFileHelper(final Context context, @Nullable final Uri parent,
|
public StoredFileHelper(final Context context, @Nullable final Uri parent,
|
||||||
|
@ -129,7 +125,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
|
|
||||||
if (path.getScheme() == null
|
if (path.getScheme() == null
|
||||||
|| path.getScheme().equalsIgnoreCase(ContentResolver.SCHEME_FILE)) {
|
|| path.getScheme().equalsIgnoreCase(ContentResolver.SCHEME_FILE)) {
|
||||||
this.ioFile = new File(URI.create(this.source));
|
this.ioPath = Paths.get(URI.create(this.source));
|
||||||
} else {
|
} else {
|
||||||
final DocumentFile file = DocumentFile.fromSingleUri(context, path);
|
final DocumentFile file = DocumentFile.fromSingleUri(context, path);
|
||||||
|
|
||||||
|
@ -187,7 +183,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
assertValid();
|
assertValid();
|
||||||
|
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
return new FileStream(ioFile);
|
return new FileStream(ioPath.toFile());
|
||||||
} else {
|
} else {
|
||||||
return new FileStreamSAF(context.getContentResolver(), docFile.getUri());
|
return new FileStreamSAF(context.getContentResolver(), docFile.getUri());
|
||||||
}
|
}
|
||||||
|
@ -211,7 +207,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
public Uri getUri() {
|
public Uri getUri() {
|
||||||
assertValid();
|
assertValid();
|
||||||
|
|
||||||
return docFile == null ? Uri.fromFile(ioFile) : docFile.getUri();
|
return docFile == null ? Uri.fromFile(ioPath.toFile()) : docFile.getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getParentUri() {
|
public Uri getParentUri() {
|
||||||
|
@ -233,7 +229,12 @@ public class StoredFileHelper implements Serializable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
return ioFile.delete();
|
try {
|
||||||
|
return Files.deleteIfExists(ioPath);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
Log.e(TAG, "Exception while deleting " + ioPath, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean res = docFile.delete();
|
final boolean res = docFile.delete();
|
||||||
|
@ -252,21 +253,30 @@ public class StoredFileHelper implements Serializable {
|
||||||
public long length() {
|
public long length() {
|
||||||
assertValid();
|
assertValid();
|
||||||
|
|
||||||
return docFile == null ? ioFile.length() : docFile.length();
|
if (docFile == null) {
|
||||||
|
try {
|
||||||
|
return Files.size(ioPath);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
Log.e(TAG, "Exception while getting the size of " + ioPath, e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return docFile.length();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canWrite() {
|
public boolean canWrite() {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return docFile == null ? ioFile.canWrite() : docFile.canWrite();
|
return docFile == null ? Files.isWritable(ioPath) : docFile.canWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return srcName;
|
return srcName;
|
||||||
} else if (docFile == null) {
|
} else if (docFile == null) {
|
||||||
return ioFile.getName();
|
return ioPath.getFileName().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String name = docFile.getName();
|
final String name = docFile.getName();
|
||||||
|
@ -287,12 +297,11 @@ public class StoredFileHelper implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean existsAsFile() {
|
public boolean existsAsFile() {
|
||||||
if (source == null || (docFile == null && ioFile == null)) {
|
if (source == null || (docFile == null && ioPath == null)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "existsAsFile called but something is null: source = ["
|
Log.d(TAG, "existsAsFile called but something is null: source = ["
|
||||||
+ (source == null ? "null => storage is invalid" : source)
|
+ (source == null ? "null => storage is invalid" : source)
|
||||||
+ "], docFile = [" + (docFile == null ? "null" : docFile)
|
+ "], docFile = [" + docFile + "], ioPath = [" + ioPath + "]");
|
||||||
+ "], ioFile = [" + (ioFile == null ? "null" : ioFile) + "]");
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +309,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
// WARNING: DocumentFile.exists() and DocumentFile.isFile() methods are slow
|
// WARNING: DocumentFile.exists() and DocumentFile.isFile() methods are slow
|
||||||
// docFile.isVirtual() means it is non-physical?
|
// docFile.isVirtual() means it is non-physical?
|
||||||
return docFile == null
|
return docFile == null
|
||||||
? (ioFile.exists() && ioFile.isFile())
|
? Files.isRegularFile(ioPath)
|
||||||
: (docFile.exists() && docFile.isFile());
|
: (docFile.exists() && docFile.isFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,8 +319,10 @@ public class StoredFileHelper implements Serializable {
|
||||||
|
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
try {
|
try {
|
||||||
result = ioFile.createNewFile();
|
Files.createFile(ioPath);
|
||||||
|
result = true;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
|
Log.e(TAG, "Exception while creating " + ioPath, e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (docTree == null) {
|
} else if (docTree == null) {
|
||||||
|
@ -332,7 +343,8 @@ public class StoredFileHelper implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
source = (docFile == null ? Uri.fromFile(ioFile) : docFile.getUri()).toString();
|
source = (docFile == null ? Uri.fromFile(ioPath.toFile()) : docFile.getUri())
|
||||||
|
.toString();
|
||||||
srcName = getName();
|
srcName = getName();
|
||||||
srcType = getType();
|
srcType = getType();
|
||||||
}
|
}
|
||||||
|
@ -352,7 +364,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
|
|
||||||
docTree = null;
|
docTree = null;
|
||||||
docFile = null;
|
docFile = null;
|
||||||
ioFile = null;
|
ioPath = null;
|
||||||
context = null;
|
context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +395,7 @@ public class StoredFileHelper implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDirect()) {
|
if (this.isDirect()) {
|
||||||
return this.ioFile.getPath().equalsIgnoreCase(storage.ioFile.getPath());
|
return this.ioPath.equals(storage.ioPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DocumentsContract.getDocumentId(this.docFile.getUri())
|
return DocumentsContract.getDocumentId(this.docFile.getUri())
|
||||||
|
|
Loading…
Reference in New Issue