Move Stored(File|Directory)Helper into NewPipe

This commit is contained in:
wb9688 2020-06-14 19:37:45 +02:00 committed by Stypox
parent 0f75024e03
commit 1164ea52f9
No known key found for this signature in database
GPG key ID: 4BDF1B40A49FDD23
18 changed files with 271 additions and 186 deletions

View file

@ -26,7 +26,7 @@ import java.util.Objects;
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.service.DownloadManagerService;
import us.shandian.giga.util.Utility;

View file

@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
import java.io.Serializable;
import java.util.Calendar;
import us.shandian.giga.io.StoredFileHelper;
import org.schabi.newpipe.streams.io.StoredFileHelper;
public abstract class Mission implements Serializable {
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 getTimestamp() {
return timestamp;
}
/**
* pre-defined content type
*/
@ -35,10 +39,6 @@ public abstract class Mission implements Serializable {
*/
public StoredFileHelper storage;
public long getTimestamp() {
return timestamp;
}
/**
* Delete the downloaded file
*
@ -57,7 +57,7 @@ public abstract class Mission implements Serializable {
@NonNull
@Override
public String toString() {
Calendar calendar = Calendar.getInstance();
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp);
return "[" + calendar.getTime().toString() + "] " + (storage.isInvalid() ? storage.getName() : storage.getUri());
}

View file

@ -17,7 +17,7 @@ import java.util.Objects;
import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.get.FinishedMission;
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

View file

@ -1,307 +0,0 @@
package us.shandian.giga.io;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.util.FilePickerActivityHelper;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME;
import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID;
public class StoredDirectoryHelper {
public final static int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
private File ioTree;
private DocumentFile docTree;
private Context context;
private final String tag;
public StoredDirectoryHelper(@NonNull Context context, @NonNull Uri path, String tag) throws IOException {
this.tag = tag;
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(path.getScheme())) {
this.ioTree = new File(URI.create(path.toString()));
return;
}
this.context = context;
try {
this.context.getContentResolver().takePersistableUriPermission(path, PERMISSION_FLAGS);
} catch (Exception e) {
throw new IOException(e);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
throw new IOException("Storage Access Framework with Directory API is not available");
this.docTree = DocumentFile.fromTreeUri(context, path);
if (this.docTree == null)
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) {
return createFile(filename, mime, false);
}
public StoredFileHelper createUniqueFile(String name, String mime) {
ArrayList<String> matches = new ArrayList<>();
String[] filename = splitFilename(name);
String lcFilename = filename[0].toLowerCase();
if (docTree == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
for (File file : ioTree.listFiles())
addIfStartWith(matches, lcFilename, file.getName());
} else {
// warning: SAF file listing is very slow
Uri docTreeChildren = DocumentsContract.buildChildDocumentsUriUsingTree(
docTree.getUri(), DocumentsContract.getDocumentId(docTree.getUri())
);
String[] projection = {COLUMN_DISPLAY_NAME};
String selection = "(LOWER(" + COLUMN_DISPLAY_NAME + ") LIKE ?%";
ContentResolver cr = context.getContentResolver();
try (Cursor cursor = cr.query(docTreeChildren, projection, selection, new String[]{lcFilename}, null)) {
if (cursor != null) {
while (cursor.moveToNext())
addIfStartWith(matches, lcFilename, cursor.getString(0));
}
}
}
if (matches.size() < 1) {
return createFile(name, mime, true);
} else {
// check if the filename is in use
String lcName = name.toLowerCase();
for (String testName : matches) {
if (testName.equals(lcName)) {
lcName = null;
break;
}
}
// check if not in use
if (lcName != null) return createFile(name, mime, true);
}
Collections.sort(matches, String::compareTo);
for (int i = 1; i < 1000; i++) {
if (Collections.binarySearch(matches, makeFileName(lcFilename, i, filename[1])) < 0)
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) {
StoredFileHelper storage;
try {
if (docTree == null)
storage = new StoredFileHelper(ioTree, filename, mime);
else
storage = new StoredFileHelper(context, docTree, filename, mime, safe);
} catch (IOException e) {
return null;
}
storage.tag = tag;
return storage;
}
public Uri getUri() {
return docTree == null ? Uri.fromFile(ioTree) : docTree.getUri();
}
public boolean exists() {
return docTree == null ? ioTree.exists() : docTree.exists();
}
/**
* Indicates whatever if is possible access using the {@code java.io} API
*
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
*/
public boolean isDirect() {
return docTree == null;
}
/**
* Only using Java I/O. Creates the directory named by this abstract pathname, including any
* necessary but nonexistent parent directories. Note that if this
* operation fails it may have succeeded in creating some of the necessary
* parent directories.
*
* @return <code>true</code> if and only if the directory was created,
* along with all necessary parent directories or already exists; <code>false</code>
* otherwise
*/
public boolean mkdirs() {
if (docTree == null) {
return ioTree.exists() || ioTree.mkdirs();
}
if (docTree.exists()) return true;
try {
DocumentFile parent;
String child = docTree.getName();
while (true) {
parent = docTree.getParentFile();
if (parent == null || child == null) break;
if (parent.exists()) return true;
parent.createDirectory(child);
child = parent.getName();// for the next iteration
}
} catch (Exception e) {
// no more parent directories or unsupported by the storage provider
}
return false;
}
public String getTag() {
return tag;
}
public Uri findFile(String filename) {
if (docTree == null) {
File res = new File(ioTree, filename);
return res.exists() ? Uri.fromFile(res) : null;
}
DocumentFile res = findFileSAFHelper(context, docTree, filename);
return res == null ? null : res.getUri();
}
public boolean canWrite() {
return docTree == null ? ioTree.canWrite() : docTree.canWrite();
}
@NonNull
@Override
public String toString() {
return (docTree == null ? Uri.fromFile(ioTree) : docTree.getUri()).toString();
}
////////////////////
// Utils
///////////////////
private static void addIfStartWith(ArrayList<String> list, @NonNull String base, String str) {
if (str == null || str.isEmpty()) return;
str = str.toLowerCase();
if (str.startsWith(base)) list.add(str);
}
private static String[] splitFilename(@NonNull String filename) {
int dotIndex = filename.lastIndexOf('.');
if (dotIndex < 0 || (dotIndex == filename.length() - 1))
return new String[]{filename, ""};
return new String[]{filename.substring(0, dotIndex), filename.substring(dotIndex)};
}
private static String makeFileName(String name, int idx, String ext) {
return name.concat(" (").concat(String.valueOf(idx)).concat(")").concat(ext);
}
/**
* Fast (but not enough) file/directory finder under the storage access framework
*
* @param context The context
* @param tree Directory where search
* @param filename Target filename
* @return A {@link DocumentFile} contain the reference, otherwise, null
*/
static DocumentFile findFileSAFHelper(@Nullable Context context, DocumentFile tree, String filename) {
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return tree.findFile(filename);// warning: this is very slow
}
if (!tree.canRead()) return null;// missing read permission
final int name = 0;
final int documentId = 1;
// LOWER() SQL function is not supported
String selection = COLUMN_DISPLAY_NAME + " = ?";
//String selection = COLUMN_DISPLAY_NAME + " LIKE ?%";
Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
tree.getUri(), DocumentsContract.getDocumentId(tree.getUri())
);
String[] projection = {COLUMN_DISPLAY_NAME, COLUMN_DOCUMENT_ID};
ContentResolver contentResolver = context.getContentResolver();
filename = filename.toLowerCase();
try (Cursor cursor = contentResolver.query(childrenUri, projection, selection, new String[]{filename}, null)) {
if (cursor == null) return null;
while (cursor.moveToNext()) {
if (cursor.isNull(name) || !cursor.getString(name).toLowerCase().startsWith(filename))
continue;
return DocumentFile.fromSingleUri(
context, DocumentsContract.buildDocumentUriUsingTree(
tree.getUri(), cursor.getString(documentId)
)
);
}
}
return null;
}
public static Intent getPicker(final Context ctx) {
if (NewPipeSettings.useStorageAccessFramework(ctx)) {
return new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
.putExtra("android.content.extra.SHOW_ADVANCED", true)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| StoredDirectoryHelper.PERMISSION_FLAGS);
} else {
return new Intent(ctx, FilePickerActivityHelper.class)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
FilePickerActivityHelper.MODE_DIR);
}
}
}

View file

@ -1,447 +0,0 @@
package us.shandian.giga.io;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import com.nononsenseapps.filepicker.Utils;
import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.streams.io.SharpStream;
import org.schabi.newpipe.util.FilePickerActivityHelper;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
public class StoredFileHelper implements Serializable {
private static final long serialVersionUID = 0L;
public static final String DEFAULT_MIME = "application/octet-stream";
private transient DocumentFile docFile;
private transient DocumentFile docTree;
private transient File ioFile;
private transient Context context;
protected String source;
private String sourceTree;
protected String tag;
private String srcName;
private String srcType;
public StoredFileHelper(final Context context, final Uri uri, final String mime) {
if (FilePickerActivityHelper.isOwnFileUri(context, uri)) {
ioFile = Utils.getFileForUri(uri);
source = Uri.fromFile(ioFile).toString();
} else {
docFile = DocumentFile.fromSingleUri(context, uri);
source = uri.toString();
}
this.context = context;
this.srcType = mime;
}
public StoredFileHelper(@Nullable Uri parent, String filename, String mime, String tag) {
this.source = null;// this instance will be "invalid" see invalidate()/isInvalid() methods
this.srcName = filename;
this.srcType = mime == null ? DEFAULT_MIME : mime;
if (parent != null) this.sourceTree = parent.toString();
this.tag = tag;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
StoredFileHelper(@Nullable Context context, DocumentFile tree, String filename, String mime, boolean safe) throws IOException {
this.docTree = tree;
this.context = context;
DocumentFile res;
if (safe) {
// no conflicts (the filename is not in use)
res = this.docTree.createFile(mime, filename);
if (res == null) throw new IOException("Cannot create the file");
} else {
res = createSAF(context, mime, filename);
}
this.docFile = res;
this.source = docFile.getUri().toString();
this.sourceTree = docTree.getUri().toString();
this.srcName = this.docFile.getName();
this.srcType = this.docFile.getType();
}
StoredFileHelper(File location, String filename, String mime) throws IOException {
this.ioFile = new File(location, filename);
if (this.ioFile.exists()) {
if (!this.ioFile.isFile() && !this.ioFile.delete())
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();
this.sourceTree = Uri.fromFile(location).toString();
this.srcName = ioFile.getName();
this.srcType = mime;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public StoredFileHelper(Context context, @Nullable Uri parent, @NonNull Uri path, String tag) throws IOException {
this.tag = tag;
this.source = path.toString();
if (path.getScheme() == null || path.getScheme().equalsIgnoreCase(ContentResolver.SCHEME_FILE)) {
this.ioFile = new File(URI.create(this.source));
} else {
DocumentFile file = DocumentFile.fromSingleUri(context, path);
if (file == null) throw new RuntimeException("SAF not available");
this.context = context;
if (file.getName() == null) {
this.source = null;
return;
} else {
this.docFile = file;
takePermissionSAF();
}
}
if (parent != null) {
if (!ContentResolver.SCHEME_FILE.equals(parent.getScheme()))
this.docTree = DocumentFile.fromTreeUri(context, parent);
this.sourceTree = parent.toString();
}
this.srcName = getName();
this.srcType = getType();
}
public static StoredFileHelper deserialize(@NonNull StoredFileHelper storage, Context context) throws IOException {
Uri treeUri = storage.sourceTree == null ? null : Uri.parse(storage.sourceTree);
if (storage.isInvalid())
return new StoredFileHelper(treeUri, storage.srcName, storage.srcType, storage.tag);
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
if (instance.srcName == null) instance.srcName = storage.srcName;
if (instance.srcType == null) instance.srcType = storage.srcType;
return instance;
}
public SharpStream getStream() throws IOException {
invalid();
if (docFile == null)
return new FileStream(ioFile);
else
return new FileStreamSAF(context.getContentResolver(), docFile.getUri());
}
/**
* Indicates whatever if is possible access using the {@code java.io} API
*
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
*/
public boolean isDirect() {
invalid();
return docFile == null;
}
public boolean isInvalid() {
return source == null;
}
public Uri getUri() {
invalid();
return docFile == null ? Uri.fromFile(ioFile) : docFile.getUri();
}
public Uri getParentUri() {
invalid();
return sourceTree == null ? null : Uri.parse(sourceTree);
}
public void truncate() throws IOException {
invalid();
try (SharpStream fs = getStream()) {
fs.setLength(0);
}
}
public boolean delete() {
if (source == null) return true;
if (docFile == null) return ioFile.delete();
boolean res = docFile.delete();
try {
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
context.getContentResolver().releasePersistableUriPermission(docFile.getUri(), flags);
} catch (Exception ex) {
// nothing to do
}
return res;
}
public long length() {
invalid();
return docFile == null ? ioFile.length() : docFile.length();
}
public boolean canWrite() {
if (source == null) return false;
return docFile == null ? ioFile.canWrite() : docFile.canWrite();
}
public String getName() {
if (source == null)
return srcName;
else if (docFile == null)
return ioFile.getName();
String name = docFile.getName();
return name == null ? srcName : name;
}
public String getType() {
if (source == null || docFile == null)
return srcType;
String type = docFile.getType();
return type == null ? srcType : type;
}
public String getTag() {
return tag;
}
public boolean existsAsFile() {
if (source == null) return false;
// WARNING: DocumentFile.exists() and DocumentFile.isFile() methods are slow
boolean exists = docFile == null ? ioFile.exists() : docFile.exists();
boolean isFile = docFile == null ? ioFile.isFile() : docFile.isFile();// ¿docFile.isVirtual() means is no-physical?
return exists && isFile;
}
public boolean create() {
invalid();
boolean result;
if (docFile == null) {
try {
result = ioFile.createNewFile();
} catch (IOException e) {
return false;
}
} else if (docTree == null) {
result = false;
} else {
if (!docTree.canRead() || !docTree.canWrite()) return false;
try {
docFile = createSAF(context, srcType, srcName);
if (docFile.getName() == null) return false;
result = true;
} catch (IOException e) {
return false;
}
}
if (result) {
source = (docFile == null ? Uri.fromFile(ioFile) : docFile.getUri()).toString();
srcName = getName();
srcType = getType();
}
return result;
}
public void invalidate() {
if (source == null) return;
srcName = getName();
srcType = getType();
source = null;
docTree = null;
docFile = null;
ioFile = null;
context = null;
}
public boolean equals(StoredFileHelper storage) {
if (this == storage) return true;
// note: do not compare tags, files can have the same parent folder
//if (stringMismatch(this.tag, storage.tag)) return false;
if (stringMismatch(getLowerCase(this.sourceTree), getLowerCase(this.sourceTree)))
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.isDirect())
return this.ioFile.getPath().equalsIgnoreCase(storage.ioFile.getPath());
return DocumentsContract.getDocumentId(
this.docFile.getUri()
).equalsIgnoreCase(DocumentsContract.getDocumentId(
storage.docFile.getUri()
));
}
@NonNull
@Override
public String toString() {
if (source == null)
return "[Invalid state] name=" + srcName + " type=" + srcType + " tag=" + tag;
else
return "sourceFile=" + source + " treeSource=" + (sourceTree == null ? "" : sourceTree) + " tag=" + tag;
}
private void invalid() {
if (source == null)
throw new IllegalStateException("In invalid state");
}
private void takePermissionSAF() throws IOException {
try {
context.getContentResolver().takePersistableUriPermission(docFile.getUri(), StoredDirectoryHelper.PERMISSION_FLAGS);
} catch (Exception e) {
if (docFile.getName() == null) throw new IOException(e);
}
}
@NonNull
private DocumentFile createSAF(@Nullable Context context, String mime, String filename)
throws IOException {
DocumentFile res = StoredDirectoryHelper.findFileSAFHelper(context, docTree, filename);
if (res != null && res.exists() && res.isDirectory()) {
if (!res.delete())
throw new IOException("Directory with the same name found but cannot delete");
res = null;
}
if (res == null) {
res = this.docTree.createFile(srcType == null ? DEFAULT_MIME : mime, filename);
if (res == null) throw new IOException("Cannot create the file");
}
return res;
}
private String getLowerCase(String str) {
return str == null ? null : str.toLowerCase();
}
private boolean stringMismatch(String str1, String str2) {
if (str1 == null && str2 == null) return false;
if ((str1 == null) != (str2 == null)) return true;
return !str1.equals(str2);
}
public static Intent getPicker(final Context ctx) {
if (NewPipeSettings.useStorageAccessFramework(ctx)) {
return new Intent(Intent.ACTION_OPEN_DOCUMENT)
.putExtra("android.content.extra.SHOW_ADVANCED", true)
.setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| StoredDirectoryHelper.PERMISSION_FLAGS);
} else {
return new Intent(ctx, FilePickerActivityHelper.class)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
.putExtra(FilePickerActivityHelper.EXTRA_SINGLE_CLICK, true)
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
FilePickerActivityHelper.MODE_FILE);
}
}
public static Intent getNewPicker(@NonNull final Context ctx, @Nullable final String startPath,
@Nullable final String filename) {
final Intent i;
if (NewPipeSettings.useStorageAccessFramework(ctx)) {
i = new Intent(Intent.ACTION_CREATE_DOCUMENT)
.putExtra("android.content.extra.SHOW_ADVANCED", true)
.setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| StoredDirectoryHelper.PERMISSION_FLAGS);
if (startPath != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
i.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse(startPath));
}
if (filename != null) {
i.putExtra(Intent.EXTRA_TITLE, filename);
}
} else {
i = new Intent(ctx, FilePickerActivityHelper.class)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_EXISTING_FILE, true)
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
FilePickerActivityHelper.MODE_NEW_FILE);
if (startPath != null || filename != null) {
File fullStartPath;
if (startPath == null) {
fullStartPath = Environment.getExternalStorageDirectory();
} else {
fullStartPath = new File(startPath);
}
if (filename != null) {
fullStartPath = new File(fullStartPath, filename);
}
i.putExtra(FilePickerActivityHelper.EXTRA_START_PATH,
fullStartPath.getAbsolutePath());
}
}
return i;
}
}

View file

@ -19,8 +19,8 @@ import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.get.FinishedMission;
import us.shandian.giga.get.Mission;
import us.shandian.giga.get.sqlite.FinishedMissionStore;
import us.shandian.giga.io.StoredDirectoryHelper;
import us.shandian.giga.io.StoredFileHelper;
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
import org.schabi.newpipe.streams.io.StoredFileHelper;
import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG;

View file

@ -47,8 +47,8 @@ import java.util.ArrayList;
import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.get.MissionRecoveryInfo;
import us.shandian.giga.io.StoredDirectoryHelper;
import us.shandian.giga.io.StoredFileHelper;
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
import org.schabi.newpipe.streams.io.StoredFileHelper;
import us.shandian.giga.postprocessing.Postprocessing;
import us.shandian.giga.service.DownloadManager.NetworkState;

View file

@ -61,7 +61,7 @@ import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.get.FinishedMission;
import us.shandian.giga.get.Mission;
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.DownloadManagerService;
import us.shandian.giga.ui.common.Deleter;

View file

@ -36,7 +36,7 @@ import java.io.File;
import java.io.IOException;
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.DownloadManagerService;
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;

View file

@ -29,7 +29,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
import us.shandian.giga.io.StoredFileHelper;
import org.schabi.newpipe.streams.io.StoredFileHelper;
public class Utility {