mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-12-23 16:40:32 +00:00
Move Stored(File|Directory)Helper into NewPipe
This commit is contained in:
parent
0f75024e03
commit
1164ea52f9
@ -49,6 +49,8 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|||||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
import org.schabi.newpipe.util.FilenameUtils;
|
import org.schabi.newpipe.util.FilenameUtils;
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
import org.schabi.newpipe.util.ListHelper;
|
||||||
@ -68,8 +70,6 @@ import icepick.Icepick;
|
|||||||
import icepick.State;
|
import icepick.State;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
import us.shandian.giga.get.MissionRecoveryInfo;
|
import us.shandian.giga.get.MissionRecoveryInfo;
|
||||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
|
||||||
import us.shandian.giga.postprocessing.Postprocessing;
|
import us.shandian.giga.postprocessing.Postprocessing;
|
||||||
import us.shandian.giga.service.DownloadManager;
|
import us.shandian.giga.service.DownloadManager;
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
|
@ -57,11 +57,11 @@ import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
|
|||||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE
|
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE
|
||||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE
|
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE
|
||||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE
|
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE
|
||||||
|
import org.schabi.newpipe.streams.io.StoredFileHelper
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper
|
import org.schabi.newpipe.util.FilePickerActivityHelper
|
||||||
import org.schabi.newpipe.util.NavigationHelper
|
import org.schabi.newpipe.util.NavigationHelper
|
||||||
import org.schabi.newpipe.util.OnClickGesture
|
import org.schabi.newpipe.util.OnClickGesture
|
||||||
import org.schabi.newpipe.util.ShareUtils
|
import org.schabi.newpipe.util.ShareUtils
|
||||||
import us.shandian.giga.io.StoredFileHelper
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
@ -34,7 +34,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.CHANNEL_URL;
|
import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.CHANNEL_URL;
|
||||||
import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.CHANNEL_URL_MODE;
|
import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.CHANNEL_URL_MODE;
|
||||||
|
@ -32,6 +32,7 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||||
import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
|
import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
|
||||||
import org.schabi.newpipe.streams.io.SharpOutputStream;
|
import org.schabi.newpipe.streams.io.SharpOutputStream;
|
||||||
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -41,7 +42,6 @@ import java.util.List;
|
|||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.rxjava3.functions.Function;
|
import io.reactivex.rxjava3.functions.Function;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
|||||||
import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
|
import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
|
||||||
import org.schabi.newpipe.ktx.ExceptionUtils;
|
import org.schabi.newpipe.ktx.ExceptionUtils;
|
||||||
import org.schabi.newpipe.streams.io.SharpInputStream;
|
import org.schabi.newpipe.streams.io.SharpInputStream;
|
||||||
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
|
|
||||||
@ -52,10 +53,9 @@ import io.reactivex.rxjava3.core.Notification;
|
|||||||
import io.reactivex.rxjava3.functions.Consumer;
|
import io.reactivex.rxjava3.functions.Consumer;
|
||||||
import io.reactivex.rxjava3.functions.Function;
|
import io.reactivex.rxjava3.functions.Function;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
import static us.shandian.giga.io.StoredFileHelper.DEFAULT_MIME;
|
import static org.schabi.newpipe.streams.io.StoredFileHelper.DEFAULT_MIME;
|
||||||
|
|
||||||
public class SubscriptionsImportService extends BaseImportExportService {
|
public class SubscriptionsImportService extends BaseImportExportService {
|
||||||
public static final int CHANNEL_URL_MODE = 0;
|
public static final int CHANNEL_URL_MODE = 0;
|
||||||
|
@ -36,8 +36,8 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import java.net.URI;
|
|||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package us.shandian.giga.io;
|
package org.schabi.newpipe.streams.io;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -24,10 +23,11 @@ import java.util.Collections;
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
public class StoredDirectoryHelper {
|
public class StoredDirectoryHelper {
|
||||||
public final static int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
public static final int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||||
|
|
||||||
private File ioTree;
|
private File ioTree;
|
||||||
private DocumentFile docTree;
|
private DocumentFile docTree;
|
||||||
@ -36,7 +36,8 @@ public class StoredDirectoryHelper {
|
|||||||
|
|
||||||
private final String tag;
|
private final String tag;
|
||||||
|
|
||||||
public StoredDirectoryHelper(@NonNull Context context, @NonNull Uri path, String tag) throws IOException {
|
public StoredDirectoryHelper(@NonNull final Context context, @NonNull final Uri path,
|
||||||
|
final String tag) throws IOException {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
|
||||||
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(path.getScheme())) {
|
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(path.getScheme())) {
|
||||||
@ -48,61 +49,59 @@ public class StoredDirectoryHelper {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.context.getContentResolver().takePersistableUriPermission(path, PERMISSION_FLAGS);
|
this.context.getContentResolver().takePersistableUriPermission(path, PERMISSION_FLAGS);
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
throw new IOException("Storage Access Framework with Directory API is not available");
|
throw new IOException("Storage Access Framework with Directory API is not available");
|
||||||
|
}
|
||||||
|
|
||||||
this.docTree = DocumentFile.fromTreeUri(context, path);
|
this.docTree = DocumentFile.fromTreeUri(context, path);
|
||||||
|
|
||||||
if (this.docTree == null)
|
if (this.docTree == null) {
|
||||||
throw new IOException("Failed to create the tree from Uri");
|
throw new IOException("Failed to create the tree from Uri");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
||||||
public StoredDirectoryHelper(@NonNull URI location, String tag) {
|
|
||||||
ioTree = new File(location);
|
|
||||||
this.tag = tag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoredFileHelper createFile(String filename, String mime) {
|
public StoredFileHelper createFile(final String filename, final String mime) {
|
||||||
return createFile(filename, mime, false);
|
return createFile(filename, mime, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoredFileHelper createUniqueFile(String name, String mime) {
|
public StoredFileHelper createUniqueFile(final String name, final String mime) {
|
||||||
ArrayList<String> matches = new ArrayList<>();
|
final ArrayList<String> matches = new ArrayList<>();
|
||||||
String[] filename = splitFilename(name);
|
final String[] filename = splitFilename(name);
|
||||||
String lcFilename = filename[0].toLowerCase();
|
final String lcFilename = filename[0].toLowerCase();
|
||||||
|
|
||||||
if (docTree == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
if (docTree == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
for (File file : ioTree.listFiles())
|
for (final File file : ioTree.listFiles()) {
|
||||||
addIfStartWith(matches, lcFilename, file.getName());
|
addIfStartWith(matches, lcFilename, file.getName());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// warning: SAF file listing is very slow
|
// warning: SAF file listing is very slow
|
||||||
Uri docTreeChildren = DocumentsContract.buildChildDocumentsUriUsingTree(
|
final Uri docTreeChildren = DocumentsContract.buildChildDocumentsUriUsingTree(
|
||||||
docTree.getUri(), DocumentsContract.getDocumentId(docTree.getUri())
|
docTree.getUri(), DocumentsContract.getDocumentId(docTree.getUri()));
|
||||||
);
|
|
||||||
|
|
||||||
String[] projection = {COLUMN_DISPLAY_NAME};
|
final String[] projection = new String[]{COLUMN_DISPLAY_NAME};
|
||||||
String selection = "(LOWER(" + COLUMN_DISPLAY_NAME + ") LIKE ?%";
|
final String selection = "(LOWER(" + COLUMN_DISPLAY_NAME + ") LIKE ?%";
|
||||||
ContentResolver cr = context.getContentResolver();
|
final ContentResolver cr = context.getContentResolver();
|
||||||
|
|
||||||
try (Cursor cursor = cr.query(docTreeChildren, projection, selection, new String[]{lcFilename}, null)) {
|
try (Cursor cursor = cr.query(docTreeChildren, projection, selection,
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (matches.size() < 1) {
|
if (matches.size() < 1) {
|
||||||
return createFile(name, mime, true);
|
return createFile(name, mime, true);
|
||||||
} else {
|
} else {
|
||||||
// check if the filename is in use
|
// check if the filename is in use
|
||||||
String lcName = name.toLowerCase();
|
String lcName = name.toLowerCase();
|
||||||
for (String testName : matches) {
|
for (final String testName : matches) {
|
||||||
if (testName.equals(lcName)) {
|
if (testName.equals(lcName)) {
|
||||||
lcName = null;
|
lcName = null;
|
||||||
break;
|
break;
|
||||||
@ -110,28 +109,34 @@ public class StoredDirectoryHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if not in use
|
// check if not in use
|
||||||
if (lcName != null) return createFile(name, mime, true);
|
if (lcName != null) {
|
||||||
|
return createFile(name, mime, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return createFile(String.valueOf(System.currentTimeMillis()).concat(filename[1]), mime, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private StoredFileHelper createFile(String filename, String mime, boolean safe) {
|
return createFile(String.valueOf(System.currentTimeMillis()).concat(filename[1]), mime,
|
||||||
StoredFileHelper storage;
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StoredFileHelper createFile(final String filename, final String mime,
|
||||||
|
final boolean safe) {
|
||||||
|
final StoredFileHelper storage;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (docTree == null)
|
if (docTree == null) {
|
||||||
storage = new StoredFileHelper(ioTree, filename, mime);
|
storage = new StoredFileHelper(ioTree, filename, mime);
|
||||||
else
|
} else {
|
||||||
storage = new StoredFileHelper(context, docTree, filename, mime, safe);
|
storage = new StoredFileHelper(context, docTree, filename, mime, safe);
|
||||||
} catch (IOException e) {
|
}
|
||||||
|
} catch (final IOException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +154,7 @@ public class StoredDirectoryHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whatever if is possible access using the {@code java.io} API
|
* Indicates whether it's using the {@code java.io} API.
|
||||||
*
|
*
|
||||||
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
|
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
|
||||||
*/
|
*/
|
||||||
@ -172,7 +177,9 @@ public class StoredDirectoryHelper {
|
|||||||
return ioTree.exists() || ioTree.mkdirs();
|
return ioTree.exists() || ioTree.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (docTree.exists()) return true;
|
if (docTree.exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DocumentFile parent;
|
DocumentFile parent;
|
||||||
@ -180,14 +187,18 @@ public class StoredDirectoryHelper {
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
parent = docTree.getParentFile();
|
parent = docTree.getParentFile();
|
||||||
if (parent == null || child == null) break;
|
if (parent == null || child == null) {
|
||||||
if (parent.exists()) return true;
|
break;
|
||||||
|
}
|
||||||
|
if (parent.exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
parent.createDirectory(child);
|
parent.createDirectory(child);
|
||||||
|
|
||||||
child = parent.getName(); // for the next iteration
|
child = parent.getName(); // for the next iteration
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (final Exception ignored) {
|
||||||
// no more parent directories or unsupported by the storage provider
|
// no more parent directories or unsupported by the storage provider
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,13 +209,13 @@ public class StoredDirectoryHelper {
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri findFile(String filename) {
|
public Uri findFile(final String filename) {
|
||||||
if (docTree == null) {
|
if (docTree == null) {
|
||||||
File res = new File(ioTree, filename);
|
final File res = new File(ioTree, filename);
|
||||||
return res.exists() ? Uri.fromFile(res) : null;
|
return res.exists() ? Uri.fromFile(res) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentFile res = findFileSAFHelper(context, docTree, filename);
|
final DocumentFile res = findFileSAFHelper(context, docTree, filename);
|
||||||
return res == null ? null : res.getUri();
|
return res == null ? null : res.getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,72 +229,82 @@ public class StoredDirectoryHelper {
|
|||||||
return (docTree == null ? Uri.fromFile(ioTree) : docTree.getUri()).toString();
|
return (docTree == null ? Uri.fromFile(ioTree) : docTree.getUri()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
// Utils
|
// Utils
|
||||||
///////////////////
|
///////////////////
|
||||||
|
|
||||||
private static void addIfStartWith(ArrayList<String> list, @NonNull String base, String str) {
|
private static void addIfStartWith(final ArrayList<String> list, @NonNull final String base,
|
||||||
if (str == null || str.isEmpty()) return;
|
final String str) {
|
||||||
str = str.toLowerCase();
|
if (isNullOrEmpty(str)) {
|
||||||
if (str.startsWith(base)) list.add(str);
|
return;
|
||||||
|
}
|
||||||
|
final String lowerStr = str.toLowerCase();
|
||||||
|
if (lowerStr.startsWith(base)) {
|
||||||
|
list.add(lowerStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] splitFilename(@NonNull String filename) {
|
private static String[] splitFilename(@NonNull final String filename) {
|
||||||
int dotIndex = filename.lastIndexOf('.');
|
final int dotIndex = filename.lastIndexOf('.');
|
||||||
|
|
||||||
if (dotIndex < 0 || (dotIndex == filename.length() - 1))
|
if (dotIndex < 0 || (dotIndex == filename.length() - 1)) {
|
||||||
return new String[]{filename, ""};
|
return new String[]{filename, ""};
|
||||||
|
}
|
||||||
|
|
||||||
return new String[]{filename.substring(0, dotIndex), filename.substring(dotIndex)};
|
return new String[]{filename.substring(0, dotIndex), filename.substring(dotIndex)};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String makeFileName(String name, int idx, 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.concat(" (").concat(String.valueOf(idx)).concat(")").concat(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast (but not enough) file/directory finder under the storage access framework
|
* Fast (but not enough) file/directory finder under the storage access framework.
|
||||||
*
|
*
|
||||||
* @param context The context
|
* @param context The context
|
||||||
* @param tree Directory where search
|
* @param tree Directory where search
|
||||||
* @param filename Target filename
|
* @param filename Target filename
|
||||||
* @return A {@link DocumentFile} contain the reference, otherwise, null
|
* @return A {@link DocumentFile} contain the reference, otherwise, null
|
||||||
*/
|
*/
|
||||||
static DocumentFile findFileSAFHelper(@Nullable Context context, DocumentFile tree, String filename) {
|
static DocumentFile findFileSAFHelper(@Nullable final Context context, final DocumentFile tree,
|
||||||
|
final String filename) {
|
||||||
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
return tree.findFile(filename); // warning: this is very slow
|
return tree.findFile(filename); // warning: this is very slow
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tree.canRead()) return null;// missing read permission
|
if (!tree.canRead()) {
|
||||||
|
return null; // missing read permission
|
||||||
|
}
|
||||||
|
|
||||||
final int name = 0;
|
final int name = 0;
|
||||||
final int documentId = 1;
|
final int documentId = 1;
|
||||||
|
|
||||||
// LOWER() SQL function is not supported
|
// LOWER() SQL function is not supported
|
||||||
String selection = COLUMN_DISPLAY_NAME + " = ?";
|
final String selection = COLUMN_DISPLAY_NAME + " = ?";
|
||||||
//String selection = COLUMN_DISPLAY_NAME + " LIKE ?%";
|
//final String selection = COLUMN_DISPLAY_NAME + " LIKE ?%";
|
||||||
|
|
||||||
Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
|
final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(tree.getUri(),
|
||||||
tree.getUri(), DocumentsContract.getDocumentId(tree.getUri())
|
DocumentsContract.getDocumentId(tree.getUri()));
|
||||||
);
|
final String[] projection = {COLUMN_DISPLAY_NAME, COLUMN_DOCUMENT_ID};
|
||||||
String[] projection = {COLUMN_DISPLAY_NAME, COLUMN_DOCUMENT_ID};
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
|
||||||
|
|
||||||
filename = filename.toLowerCase();
|
final String lowerFilename = filename.toLowerCase();
|
||||||
|
|
||||||
try (Cursor cursor = contentResolver.query(childrenUri, projection, selection, new String[]{filename}, null)) {
|
try (Cursor cursor = contentResolver.query(childrenUri, projection, selection,
|
||||||
if (cursor == null) return null;
|
new String[]{lowerFilename}, null)) {
|
||||||
|
if (cursor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
if (cursor.isNull(name) || !cursor.getString(name).toLowerCase().startsWith(filename))
|
if (cursor.isNull(name)
|
||||||
|
|| !cursor.getString(name).toLowerCase().startsWith(lowerFilename)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
return DocumentFile.fromSingleUri(
|
return DocumentFile.fromSingleUri(context,
|
||||||
context, DocumentsContract.buildDocumentUriUsingTree(
|
DocumentsContract.buildDocumentUriUsingTree(tree.getUri(),
|
||||||
tree.getUri(), cursor.getString(documentId)
|
cursor.getString(documentId)));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package us.shandian.giga.io;
|
package org.schabi.newpipe.streams.io;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@ -16,7 +16,6 @@ import androidx.documentfile.provider.DocumentFile;
|
|||||||
import com.nononsenseapps.filepicker.Utils;
|
import com.nononsenseapps.filepicker.Utils;
|
||||||
|
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
import org.schabi.newpipe.streams.io.SharpStream;
|
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -24,6 +23,9 @@ import java.io.IOException;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
|
import us.shandian.giga.io.FileStream;
|
||||||
|
import us.shandian.giga.io.FileStreamSAF;
|
||||||
|
|
||||||
public class StoredFileHelper implements Serializable {
|
public class StoredFileHelper implements Serializable {
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
public static final String DEFAULT_MIME = "application/octet-stream";
|
public static final String DEFAULT_MIME = "application/octet-stream";
|
||||||
@ -54,27 +56,34 @@ public class StoredFileHelper implements Serializable {
|
|||||||
this.srcType = mime;
|
this.srcType = mime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoredFileHelper(@Nullable Uri parent, String filename, String mime, String tag) {
|
public StoredFileHelper(@Nullable final Uri parent, final String filename, final String mime,
|
||||||
|
final String tag) {
|
||||||
this.source = null; // this instance will be "invalid" see invalidate()/isInvalid() methods
|
this.source = null; // this instance will be "invalid" see invalidate()/isInvalid() methods
|
||||||
|
|
||||||
this.srcName = filename;
|
this.srcName = filename;
|
||||||
this.srcType = mime == null ? DEFAULT_MIME : mime;
|
this.srcType = mime == null ? DEFAULT_MIME : mime;
|
||||||
if (parent != null) this.sourceTree = parent.toString();
|
if (parent != null) {
|
||||||
|
this.sourceTree = parent.toString();
|
||||||
|
}
|
||||||
|
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
StoredFileHelper(@Nullable Context context, DocumentFile tree, String filename, String mime, boolean safe) throws IOException {
|
StoredFileHelper(@Nullable final Context context, final DocumentFile tree,
|
||||||
|
final String filename, final String mime, final boolean safe)
|
||||||
|
throws IOException {
|
||||||
this.docTree = tree;
|
this.docTree = tree;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
DocumentFile res;
|
final DocumentFile res;
|
||||||
|
|
||||||
if (safe) {
|
if (safe) {
|
||||||
// no conflicts (the filename is not in use)
|
// no conflicts (the filename is not in use)
|
||||||
res = this.docTree.createFile(mime, filename);
|
res = this.docTree.createFile(mime, filename);
|
||||||
if (res == null) throw new IOException("Cannot create the file");
|
if (res == null) {
|
||||||
|
throw new IOException("Cannot create the file");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res = createSAF(context, mime, filename);
|
res = createSAF(context, mime, filename);
|
||||||
}
|
}
|
||||||
@ -88,16 +97,20 @@ public class StoredFileHelper implements Serializable {
|
|||||||
this.srcType = this.docFile.getType();
|
this.srcType = this.docFile.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredFileHelper(File location, String filename, String mime) throws IOException {
|
StoredFileHelper(final File location, final String filename, final String mime)
|
||||||
|
throws IOException {
|
||||||
this.ioFile = new File(location, filename);
|
this.ioFile = new File(location, filename);
|
||||||
|
|
||||||
if (this.ioFile.exists()) {
|
if (this.ioFile.exists()) {
|
||||||
if (!this.ioFile.isFile() && !this.ioFile.delete())
|
if (!this.ioFile.isFile() && !this.ioFile.delete()) {
|
||||||
throw new IOException("The filename is already in use by non-file entity and cannot overwrite it");
|
throw new IOException("The filename is already in use by non-file entity "
|
||||||
|
+ "and cannot overwrite it");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!this.ioFile.createNewFile())
|
if (!this.ioFile.createNewFile()) {
|
||||||
throw new IOException("Cannot create the file");
|
throw new IOException("Cannot create the file");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.source = Uri.fromFile(this.ioFile).toString();
|
this.source = Uri.fromFile(this.ioFile).toString();
|
||||||
this.sourceTree = Uri.fromFile(location).toString();
|
this.sourceTree = Uri.fromFile(location).toString();
|
||||||
@ -107,16 +120,20 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||||
public StoredFileHelper(Context context, @Nullable Uri parent, @NonNull Uri path, String tag) throws IOException {
|
public StoredFileHelper(final Context context, @Nullable final Uri parent,
|
||||||
|
@NonNull final Uri path, final String tag) throws IOException {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.source = path.toString();
|
this.source = path.toString();
|
||||||
|
|
||||||
if (path.getScheme() == null || path.getScheme().equalsIgnoreCase(ContentResolver.SCHEME_FILE)) {
|
if (path.getScheme() == null
|
||||||
|
|| path.getScheme().equalsIgnoreCase(ContentResolver.SCHEME_FILE)) {
|
||||||
this.ioFile = new File(URI.create(this.source));
|
this.ioFile = new File(URI.create(this.source));
|
||||||
} else {
|
} else {
|
||||||
DocumentFile file = DocumentFile.fromSingleUri(context, path);
|
final DocumentFile file = DocumentFile.fromSingleUri(context, path);
|
||||||
|
|
||||||
if (file == null) throw new RuntimeException("SAF not available");
|
if (file == null) {
|
||||||
|
throw new RuntimeException("SAF not available");
|
||||||
|
}
|
||||||
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
@ -130,8 +147,9 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
if (!ContentResolver.SCHEME_FILE.equals(parent.getScheme()))
|
if (!ContentResolver.SCHEME_FILE.equals(parent.getScheme())) {
|
||||||
this.docTree = DocumentFile.fromTreeUri(context, parent);
|
this.docTree = DocumentFile.fromTreeUri(context, parent);
|
||||||
|
}
|
||||||
|
|
||||||
this.sourceTree = parent.toString();
|
this.sourceTree = parent.toString();
|
||||||
}
|
}
|
||||||
@ -141,37 +159,45 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static StoredFileHelper deserialize(@NonNull StoredFileHelper storage, Context context) throws IOException {
|
public static StoredFileHelper deserialize(@NonNull final StoredFileHelper storage,
|
||||||
Uri treeUri = storage.sourceTree == null ? null : Uri.parse(storage.sourceTree);
|
final Context context) throws IOException {
|
||||||
|
final Uri treeUri = storage.sourceTree == null ? null : Uri.parse(storage.sourceTree);
|
||||||
|
|
||||||
if (storage.isInvalid())
|
if (storage.isInvalid()) {
|
||||||
return new StoredFileHelper(treeUri, storage.srcName, storage.srcType, storage.tag);
|
return new StoredFileHelper(treeUri, storage.srcName, storage.srcType, storage.tag);
|
||||||
|
}
|
||||||
|
|
||||||
StoredFileHelper instance = new StoredFileHelper(context, treeUri, Uri.parse(storage.source), storage.tag);
|
final StoredFileHelper instance = new StoredFileHelper(context, treeUri,
|
||||||
|
Uri.parse(storage.source), storage.tag);
|
||||||
|
|
||||||
// under SAF, if the target document is deleted, conserve the filename and mime
|
// under SAF, if the target document is deleted, conserve the filename and mime
|
||||||
if (instance.srcName == null) instance.srcName = storage.srcName;
|
if (instance.srcName == null) {
|
||||||
if (instance.srcType == null) instance.srcType = storage.srcType;
|
instance.srcName = storage.srcName;
|
||||||
|
}
|
||||||
|
if (instance.srcType == null) {
|
||||||
|
instance.srcType = storage.srcType;
|
||||||
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharpStream getStream() throws IOException {
|
public SharpStream getStream() throws IOException {
|
||||||
invalid();
|
assertValid();
|
||||||
|
|
||||||
if (docFile == null)
|
if (docFile == null) {
|
||||||
return new FileStream(ioFile);
|
return new FileStream(ioFile);
|
||||||
else
|
} else {
|
||||||
return new FileStreamSAF(context.getContentResolver(), docFile.getUri());
|
return new FileStreamSAF(context.getContentResolver(), docFile.getUri());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whatever if is possible access using the {@code java.io} API
|
* Indicates whether it's using the {@code java.io} API.
|
||||||
*
|
*
|
||||||
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
|
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
|
||||||
*/
|
*/
|
||||||
public boolean isDirect() {
|
public boolean isDirect() {
|
||||||
invalid();
|
assertValid();
|
||||||
|
|
||||||
return docFile == null;
|
return docFile == null;
|
||||||
}
|
}
|
||||||
@ -181,19 +207,19 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Uri getUri() {
|
public Uri getUri() {
|
||||||
invalid();
|
assertValid();
|
||||||
|
|
||||||
return docFile == null ? Uri.fromFile(ioFile) : docFile.getUri();
|
return docFile == null ? Uri.fromFile(ioFile) : docFile.getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getParentUri() {
|
public Uri getParentUri() {
|
||||||
invalid();
|
assertValid();
|
||||||
|
|
||||||
return sourceTree == null ? null : Uri.parse(sourceTree);
|
return sourceTree == null ? null : Uri.parse(sourceTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void truncate() throws IOException {
|
public void truncate() throws IOException {
|
||||||
invalid();
|
assertValid();
|
||||||
|
|
||||||
try (SharpStream fs = getStream()) {
|
try (SharpStream fs = getStream()) {
|
||||||
fs.setLength(0);
|
fs.setLength(0);
|
||||||
@ -201,16 +227,20 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean delete() {
|
public boolean delete() {
|
||||||
if (source == null) return true;
|
if (source == null) {
|
||||||
if (docFile == null) return ioFile.delete();
|
return true;
|
||||||
|
}
|
||||||
|
if (docFile == null) {
|
||||||
|
return ioFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean res = docFile.delete();
|
||||||
boolean res = docFile.delete();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||||
context.getContentResolver().releasePersistableUriPermission(docFile.getUri(), flags);
|
context.getContentResolver().releasePersistableUriPermission(docFile.getUri(), flags);
|
||||||
} catch (Exception ex) {
|
} catch (final Exception ex) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,31 +248,35 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long length() {
|
public long length() {
|
||||||
invalid();
|
assertValid();
|
||||||
|
|
||||||
return docFile == null ? ioFile.length() : docFile.length();
|
return docFile == null ? ioFile.length() : docFile.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canWrite() {
|
public boolean canWrite() {
|
||||||
if (source == null) return false;
|
if (source == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return docFile == null ? ioFile.canWrite() : docFile.canWrite();
|
return docFile == null ? ioFile.canWrite() : 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 ioFile.getName();
|
||||||
|
}
|
||||||
|
|
||||||
String name = docFile.getName();
|
final String name = docFile.getName();
|
||||||
return name == null ? srcName : name;
|
return name == null ? srcName : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
if (source == null || docFile == null)
|
if (source == null || docFile == null) {
|
||||||
return srcType;
|
return srcType;
|
||||||
|
}
|
||||||
|
|
||||||
String type = docFile.getType();
|
final String type = docFile.getType();
|
||||||
return type == null ? srcType : type;
|
return type == null ? srcType : type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,34 +285,41 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean existsAsFile() {
|
public boolean existsAsFile() {
|
||||||
if (source == null) return false;
|
if (source == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// WARNING: DocumentFile.exists() and DocumentFile.isFile() methods are slow
|
// WARNING: DocumentFile.exists() and DocumentFile.isFile() methods are slow
|
||||||
boolean exists = docFile == null ? ioFile.exists() : docFile.exists();
|
final boolean exists = docFile == null ? ioFile.exists() : docFile.exists();
|
||||||
boolean isFile = docFile == null ? ioFile.isFile() : docFile.isFile();// ¿docFile.isVirtual() means is no-physical?
|
// ¿docFile.isVirtual() means is no-physical?
|
||||||
|
final boolean isFile = docFile == null ? ioFile.isFile() : docFile.isFile();
|
||||||
|
|
||||||
return exists && isFile;
|
return exists && isFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean create() {
|
public boolean create() {
|
||||||
invalid();
|
assertValid();
|
||||||
boolean result;
|
final boolean result;
|
||||||
|
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
try {
|
try {
|
||||||
result = ioFile.createNewFile();
|
result = ioFile.createNewFile();
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (docTree == null) {
|
} else if (docTree == null) {
|
||||||
result = false;
|
result = false;
|
||||||
} else {
|
} else {
|
||||||
if (!docTree.canRead() || !docTree.canWrite()) return false;
|
if (!docTree.canRead() || !docTree.canWrite()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
docFile = createSAF(context, srcType, srcName);
|
docFile = createSAF(context, srcType, srcName);
|
||||||
if (docFile.getName() == null) return false;
|
if (docFile.getName() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
result = true;
|
result = true;
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,7 +334,9 @@ public class StoredFileHelper implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
if (source == null) return;
|
if (source == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
srcName = getName();
|
srcName = getName();
|
||||||
srcType = getType();
|
srcType = getType();
|
||||||
@ -306,81 +349,102 @@ public class StoredFileHelper implements Serializable {
|
|||||||
context = null;
|
context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(StoredFileHelper storage) {
|
public boolean equals(final StoredFileHelper storage) {
|
||||||
if (this == storage) return true;
|
if (this == storage) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// note: do not compare tags, files can have the same parent folder
|
// note: do not compare tags, files can have the same parent folder
|
||||||
//if (stringMismatch(this.tag, storage.tag)) return false;
|
//if (stringMismatch(this.tag, storage.tag)) return false;
|
||||||
|
|
||||||
if (stringMismatch(getLowerCase(this.sourceTree), getLowerCase(this.sourceTree)))
|
if (stringMismatch(getLowerCase(this.sourceTree), getLowerCase(this.sourceTree))) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this.isInvalid() || storage.isInvalid()) {
|
|
||||||
if (this.srcName == null || storage.srcName == null || this.srcType == null || storage.srcType == null) return false;
|
|
||||||
return this.srcName.equalsIgnoreCase(storage.srcName) && this.srcType.equalsIgnoreCase(storage.srcType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDirect() != storage.isDirect()) return false;
|
if (this.isInvalid() || storage.isInvalid()) {
|
||||||
|
if (this.srcName == null || storage.srcName == null || this.srcType == null
|
||||||
|
|| storage.srcType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isDirect())
|
return this.srcName.equalsIgnoreCase(storage.srcName)
|
||||||
|
&& this.srcType.equalsIgnoreCase(storage.srcType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isDirect() != storage.isDirect()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isDirect()) {
|
||||||
return this.ioFile.getPath().equalsIgnoreCase(storage.ioFile.getPath());
|
return this.ioFile.getPath().equalsIgnoreCase(storage.ioFile.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
return DocumentsContract.getDocumentId(
|
return DocumentsContract.getDocumentId(this.docFile.getUri())
|
||||||
this.docFile.getUri()
|
.equalsIgnoreCase(DocumentsContract.getDocumentId(storage.docFile.getUri()));
|
||||||
).equalsIgnoreCase(DocumentsContract.getDocumentId(
|
|
||||||
storage.docFile.getUri()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (source == null)
|
if (source == null) {
|
||||||
return "[Invalid state] name=" + srcName + " type=" + srcType + " tag=" + tag;
|
return "[Invalid state] name=" + srcName + " type=" + srcType + " tag=" + tag;
|
||||||
else
|
} else {
|
||||||
return "sourceFile=" + source + " treeSource=" + (sourceTree == null ? "" : sourceTree) + " tag=" + tag;
|
return "sourceFile=" + source + " treeSource=" + (sourceTree == null ? "" : sourceTree)
|
||||||
|
+ " tag=" + tag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void invalid() {
|
private void assertValid() {
|
||||||
if (source == null)
|
if (source == null) {
|
||||||
throw new IllegalStateException("In invalid state");
|
throw new IllegalStateException("In invalid state");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void takePermissionSAF() throws IOException {
|
private void takePermissionSAF() throws IOException {
|
||||||
try {
|
try {
|
||||||
context.getContentResolver().takePersistableUriPermission(docFile.getUri(), StoredDirectoryHelper.PERMISSION_FLAGS);
|
context.getContentResolver().takePersistableUriPermission(docFile.getUri(),
|
||||||
} catch (Exception e) {
|
StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
if (docFile.getName() == null) throw new IOException(e);
|
} catch (final Exception e) {
|
||||||
|
if (docFile.getName() == null) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private DocumentFile createSAF(@Nullable Context context, String mime, String filename)
|
private DocumentFile createSAF(@Nullable final Context ctx, final String mime,
|
||||||
throws IOException {
|
final String filename) throws IOException {
|
||||||
DocumentFile res = StoredDirectoryHelper.findFileSAFHelper(context, docTree, filename);
|
DocumentFile res = StoredDirectoryHelper.findFileSAFHelper(ctx, docTree, filename);
|
||||||
|
|
||||||
if (res != null && res.exists() && res.isDirectory()) {
|
if (res != null && res.exists() && res.isDirectory()) {
|
||||||
if (!res.delete())
|
if (!res.delete()) {
|
||||||
throw new IOException("Directory with the same name found but cannot delete");
|
throw new IOException("Directory with the same name found but cannot delete");
|
||||||
|
}
|
||||||
res = null;
|
res = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == null) {
|
if (res == null) {
|
||||||
res = this.docTree.createFile(srcType == null ? DEFAULT_MIME : mime, filename);
|
res = this.docTree.createFile(srcType == null ? DEFAULT_MIME : mime, filename);
|
||||||
if (res == null) throw new IOException("Cannot create the file");
|
if (res == null) {
|
||||||
|
throw new IOException("Cannot create the file");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLowerCase(String str) {
|
private String getLowerCase(final String str) {
|
||||||
return str == null ? null : str.toLowerCase();
|
return str == null ? null : str.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean stringMismatch(String str1, String str2) {
|
private boolean stringMismatch(final String str1, final String str2) {
|
||||||
if (str1 == null && str2 == null) return false;
|
if (str1 == null && str2 == null) {
|
||||||
if ((str1 == null) != (str2 == null)) return true;
|
return false;
|
||||||
|
}
|
||||||
|
if ((str1 == null) != (str2 == null)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return !str1.equals(str2);
|
return !str1.equals(str2);
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ import java.util.zip.ZipEntry;
|
|||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 28.01.18.
|
* Created by Christian Schabesberger on 28.01.18.
|
||||||
|
@ -26,7 +26,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import us.shandian.giga.postprocessing.Postprocessing;
|
import us.shandian.giga.postprocessing.Postprocessing;
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
import us.shandian.giga.util.Utility;
|
import us.shandian.giga.util.Utility;
|
||||||
|
@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
public abstract class Mission implements Serializable {
|
public abstract class Mission implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;// last bump: 27 march 2019
|
private static final long serialVersionUID = 1L;// last bump: 27 march 2019
|
||||||
@ -25,6 +25,10 @@ public abstract class Mission implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public long timestamp;
|
public long timestamp;
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pre-defined content type
|
* pre-defined content type
|
||||||
*/
|
*/
|
||||||
@ -35,10 +39,6 @@ public abstract class Mission implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public StoredFileHelper storage;
|
public StoredFileHelper storage;
|
||||||
|
|
||||||
public long getTimestamp() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the downloaded file
|
* Delete the downloaded file
|
||||||
*
|
*
|
||||||
@ -57,7 +57,7 @@ public abstract class Mission implements Serializable {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
Calendar calendar = Calendar.getInstance();
|
final Calendar calendar = Calendar.getInstance();
|
||||||
calendar.setTimeInMillis(timestamp);
|
calendar.setTimeInMillis(timestamp);
|
||||||
return "[" + calendar.getTime().toString() + "] " + (storage.isInvalid() ? storage.getName() : storage.getUri());
|
return "[" + calendar.getTime().toString() + "] " + (storage.isInvalid() ? storage.getName() : storage.getUri());
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import java.util.Objects;
|
|||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
import us.shandian.giga.get.FinishedMission;
|
import us.shandian.giga.get.FinishedMission;
|
||||||
import us.shandian.giga.get.Mission;
|
import us.shandian.giga.get.Mission;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SQLite helper to store finished {@link us.shandian.giga.get.FinishedMission}'s
|
* SQLite helper to store finished {@link us.shandian.giga.get.FinishedMission}'s
|
||||||
|
@ -19,8 +19,8 @@ import us.shandian.giga.get.DownloadMission;
|
|||||||
import us.shandian.giga.get.FinishedMission;
|
import us.shandian.giga.get.FinishedMission;
|
||||||
import us.shandian.giga.get.Mission;
|
import us.shandian.giga.get.Mission;
|
||||||
import us.shandian.giga.get.sqlite.FinishedMissionStore;
|
import us.shandian.giga.get.sqlite.FinishedMissionStore;
|
||||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import us.shandian.giga.util.Utility;
|
import us.shandian.giga.util.Utility;
|
||||||
|
|
||||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||||
|
@ -47,8 +47,8 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
import us.shandian.giga.get.MissionRecoveryInfo;
|
import us.shandian.giga.get.MissionRecoveryInfo;
|
||||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import us.shandian.giga.postprocessing.Postprocessing;
|
import us.shandian.giga.postprocessing.Postprocessing;
|
||||||
import us.shandian.giga.service.DownloadManager.NetworkState;
|
import us.shandian.giga.service.DownloadManager.NetworkState;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ import us.shandian.giga.get.DownloadMission;
|
|||||||
import us.shandian.giga.get.FinishedMission;
|
import us.shandian.giga.get.FinishedMission;
|
||||||
import us.shandian.giga.get.Mission;
|
import us.shandian.giga.get.Mission;
|
||||||
import us.shandian.giga.get.MissionRecoveryInfo;
|
import us.shandian.giga.get.MissionRecoveryInfo;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import us.shandian.giga.service.DownloadManager;
|
import us.shandian.giga.service.DownloadManager;
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
import us.shandian.giga.ui.common.Deleter;
|
import us.shandian.giga.ui.common.Deleter;
|
||||||
|
@ -36,7 +36,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import us.shandian.giga.service.DownloadManager;
|
import us.shandian.giga.service.DownloadManager;
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
|
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
|
||||||
|
@ -29,7 +29,7 @@ import java.security.MessageDigest;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import us.shandian.giga.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
|
||||||
public class Utility {
|
public class Utility {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user