Support SAF properly

This commit is contained in:
wb9688 2020-06-13 17:29:57 +02:00 committed by Stypox
parent 1e09a1768e
commit 0f75024e03
No known key found for this signature in database
GPG key ID: 4BDF1B40A49FDD23
23 changed files with 451 additions and 311 deletions

View file

@ -1,61 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package us.shandian.giga.io;
import androidx.annotation.NonNull;
import org.schabi.newpipe.streams.io.SharpStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Wrapper for the classic {@link java.io.InputStream}
*
* @author kapodamy
*/
public class SharpInputStream extends InputStream {
private final SharpStream base;
public SharpInputStream(SharpStream base) throws IOException {
if (!base.canRead()) {
throw new IOException("The provided stream is not readable");
}
this.base = base;
}
@Override
public int read() throws IOException {
return base.read();
}
@Override
public int read(@NonNull byte[] bytes) throws IOException {
return base.read(bytes);
}
@Override
public int read(@NonNull byte[] bytes, int i, int i1) throws IOException {
return base.read(bytes, i, i1);
}
@Override
public long skip(long l) throws IOException {
return base.skip(l);
}
@Override
public int available() {
long res = base.available();
return res > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) res;
}
@Override
public void close() {
base.close();
}
}

View file

@ -13,6 +13,9 @@ 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;
@ -287,4 +290,18 @@ public class StoredDirectoryHelper {
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

@ -6,14 +6,18 @@ 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 androidx.fragment.app.Fragment;
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;
@ -37,6 +41,19 @@ public class StoredFileHelper implements Serializable {
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
@ -139,22 +156,6 @@ public class StoredFileHelper implements Serializable {
return instance;
}
public static void requestSafWithFileCreation(@NonNull Fragment who, int requestCode, String filename, String mime) {
// SAF notes:
// ACTION_OPEN_DOCUMENT Do not let you create the file, useful for overwrite files
// ACTION_CREATE_DOCUMENT No overwrite support, useless the file provider resolve the conflict
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType(mime)
.putExtra(Intent.EXTRA_TITLE, filename)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | StoredDirectoryHelper.PERMISSION_FLAGS)
.putExtra("android.content.extra.SHOW_ADVANCED", true);// hack, show all storage disks
who.startActivityForResult(intent, requestCode);
}
public SharpStream getStream() throws IOException {
invalid();
@ -383,4 +384,64 @@ public class StoredFileHelper implements Serializable {
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

@ -242,27 +242,21 @@ public class MissionsFragment extends Fragment {
private void recoverMission(@NonNull DownloadMission mission) {
unsafeMissionTarget = mission;
final String startPath;
if (NewPipeSettings.useStorageAccessFramework(mContext)) {
StoredFileHelper.requestSafWithFileCreation(
MissionsFragment.this,
REQUEST_DOWNLOAD_SAVE_AS,
mission.storage.getName(),
mission.storage.getType()
);
startPath = null;
} else {
File initialSavePath;
if (DownloadManager.TAG_VIDEO.equals(mission.storage.getType()))
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MOVIES);
else
final File initialSavePath;
if (DownloadManager.TAG_AUDIO.equals(mission.storage.getType())) {
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MUSIC);
initialSavePath = new File(initialSavePath, mission.storage.getName());
startActivityForResult(
FilePickerActivityHelper.chooseFileToSave(mContext, initialSavePath.getAbsolutePath()),
REQUEST_DOWNLOAD_SAVE_AS
);
} else {
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MOVIES);
}
startPath = initialSavePath.getAbsolutePath();
}
startActivityForResult(StoredFileHelper.getNewPicker(mContext, startPath,
mission.storage.getName()), REQUEST_DOWNLOAD_SAVE_AS);
}
@Override