Skip to content

Commit 0f75024

Browse files
wb9688Stypox
authored andcommitted
Support SAF properly
1 parent 1e09a17 commit 0f75024

23 files changed

+444
-304
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
android:icon="@mipmap/ic_launcher"
2323
android:label="@string/app_name"
2424
android:logo="@mipmap/ic_launcher"
25-
android:requestLegacyExternalStorage="true"
2625
android:theme="@style/OpeningTheme"
2726
android:resizeableActivity="true"
2827
tools:ignore="AllowBackup">

app/src/main/java/org/schabi/newpipe/App.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.schabi.newpipe.extractor.NewPipe;
2828
import org.schabi.newpipe.extractor.downloader.Downloader;
2929
import org.schabi.newpipe.ktx.ExceptionUtils;
30-
import org.schabi.newpipe.settings.SettingsActivity;
30+
import org.schabi.newpipe.settings.NewPipeSettings;
3131
import org.schabi.newpipe.util.Localization;
3232
import org.schabi.newpipe.util.ServiceHelper;
3333
import org.schabi.newpipe.util.StateSaver;
@@ -91,7 +91,7 @@ public void onCreate() {
9191
app = this;
9292

9393
// Initialize settings first because others inits can use its values
94-
SettingsActivity.initSettings(this);
94+
NewPipeSettings.initSettings(this);
9595

9696
NewPipe.init(getDownloader(),
9797
Localization.getPreferredLocalization(this),

app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java

Lines changed: 85 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public class DownloadDialog extends DialogFragment
8383
private static final String TAG = "DialogFragment";
8484
private static final boolean DEBUG = MainActivity.DEBUG;
8585
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
86+
private static final int REQUEST_DOWNLOAD_PICK_VIDEO_FOLDER = 0x789E;
87+
private static final int REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER = 0x789F;
8688

8789
@State
8890
StreamInfo currentInfo;
@@ -116,6 +118,10 @@ public class DownloadDialog extends DialogFragment
116118

117119
private SharedPreferences prefs;
118120

121+
// Variables for file name and MIME type when picking new folder because it's not set yet
122+
private String filenameTmp;
123+
private String mimeTmp;
124+
119125
public static DownloadDialog newInstance(final StreamInfo info) {
120126
final DownloadDialog dialog = new DownloadDialog();
121127
dialog.setInfo(info);
@@ -374,12 +380,16 @@ public void onSaveInstanceState(@NonNull final Bundle outState) {
374380
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
375381
super.onActivityResult(requestCode, resultCode, data);
376382

377-
if (requestCode == REQUEST_DOWNLOAD_SAVE_AS && resultCode == Activity.RESULT_OK) {
378-
if (data.getData() == null) {
379-
showFailedDialog(R.string.general_error);
380-
return;
381-
}
383+
if (resultCode != Activity.RESULT_OK) {
384+
return;
385+
}
382386

387+
if (data.getData() == null) {
388+
showFailedDialog(R.string.general_error);
389+
return;
390+
}
391+
392+
if (requestCode == REQUEST_DOWNLOAD_SAVE_AS) {
383393
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
384394
final File file = Utils.getFileForUri(data.getData());
385395
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
@@ -396,6 +406,37 @@ public void onActivityResult(final int requestCode, final int resultCode, final
396406
// check if the selected file was previously used
397407
checkSelectedDownload(null, data.getData(), docFile.getName(),
398408
docFile.getType());
409+
} else if (requestCode == REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER
410+
|| requestCode == REQUEST_DOWNLOAD_PICK_VIDEO_FOLDER) {
411+
Uri uri = data.getData();
412+
if (FilePickerActivityHelper.isOwnFileUri(context, uri)) {
413+
uri = Uri.fromFile(Utils.getFileForUri(uri));
414+
} else {
415+
context.grantUriPermission(context.getPackageName(), uri,
416+
StoredDirectoryHelper.PERMISSION_FLAGS);
417+
}
418+
419+
final String key;
420+
final String tag;
421+
if (requestCode == REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER) {
422+
key = getString(R.string.download_path_audio_key);
423+
tag = DownloadManager.TAG_AUDIO;
424+
} else {
425+
key = getString(R.string.download_path_video_key);
426+
tag = DownloadManager.TAG_VIDEO;
427+
}
428+
429+
PreferenceManager.getDefaultSharedPreferences(context).edit()
430+
.putString(key, uri.toString()).apply();
431+
432+
try {
433+
final StoredDirectoryHelper mainStorage
434+
= new StoredDirectoryHelper(context, uri, tag);
435+
checkSelectedDownload(mainStorage, mainStorage.findFile(filenameTmp),
436+
filenameTmp, mimeTmp);
437+
} catch (final IOException e) {
438+
showFailedDialog(R.string.general_error);
439+
}
399440
}
400441
}
401442

@@ -603,84 +644,89 @@ private void showFailedDialog(@StringRes final int msg) {
603644
private void prepareSelectedDownload() {
604645
final StoredDirectoryHelper mainStorage;
605646
final MediaFormat format;
606-
final String mime;
607647
final String selectedMediaType;
608648

609649
// first, build the filename and get the output folder (if possible)
610650
// later, run a very very very large file checking logic
611651

612-
String filename = getNameEditText().concat(".");
652+
filenameTmp = getNameEditText().concat(".");
613653

614654
switch (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()) {
615655
case R.id.audio_button:
616656
selectedMediaType = getString(R.string.last_download_type_audio_key);
617657
mainStorage = mainStorageAudio;
618658
format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat();
619-
switch (format) {
620-
case WEBMA_OPUS:
621-
mime = "audio/ogg";
622-
filename += "opus";
623-
break;
624-
default:
625-
mime = format.mimeType;
626-
filename += format.suffix;
627-
break;
659+
if (format == MediaFormat.WEBMA_OPUS) {
660+
mimeTmp = "audio/ogg";
661+
filenameTmp += "opus";
662+
} else {
663+
mimeTmp = format.mimeType;
664+
filenameTmp += format.suffix;
628665
}
629666
break;
630667
case R.id.video_button:
631668
selectedMediaType = getString(R.string.last_download_type_video_key);
632669
mainStorage = mainStorageVideo;
633670
format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat();
634-
mime = format.mimeType;
635-
filename += format.suffix;
671+
mimeTmp = format.mimeType;
672+
filenameTmp += format.suffix;
636673
break;
637674
case R.id.subtitle_button:
638675
selectedMediaType = getString(R.string.last_download_type_subtitle_key);
639676
mainStorage = mainStorageVideo; // subtitle & video files go together
640677
format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat();
641-
mime = format.mimeType;
642-
filename += (format == MediaFormat.TTML ? MediaFormat.SRT : format).suffix;
678+
mimeTmp = format.mimeType;
679+
filenameTmp += (format == MediaFormat.TTML ? MediaFormat.SRT : format).suffix;
643680
break;
644681
default:
645682
throw new RuntimeException("No stream selected");
646683
}
647684

648-
if (mainStorage == null || askForSavePath) {
649-
// This part is called if with SAF preferred:
650-
// * older android version running
651-
// * save path not defined (via download settings)
652-
// * the user checked the "ask where to download" option
653-
654-
if (!askForSavePath) {
655-
Toast.makeText(context, getString(R.string.no_available_dir),
656-
Toast.LENGTH_LONG).show();
685+
if (!askForSavePath && (mainStorage == null || (mainStorage.isDirect()
686+
== NewPipeSettings.useStorageAccessFramework(context)))) {
687+
// Pick new download folder if one of:
688+
// - Download folder is not set
689+
// - Download folder uses SAF while SAF is disabled
690+
// - Download folder doesn't use SAF while SAF is enabled
691+
Toast.makeText(context, getString(R.string.no_dir_yet),
692+
Toast.LENGTH_LONG).show();
693+
694+
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button) {
695+
startActivityForResult(StoredDirectoryHelper.getPicker(context),
696+
REQUEST_DOWNLOAD_PICK_AUDIO_FOLDER);
697+
} else {
698+
startActivityForResult(StoredDirectoryHelper.getPicker(context),
699+
REQUEST_DOWNLOAD_PICK_VIDEO_FOLDER);
657700
}
658701

702+
return;
703+
}
704+
705+
if (askForSavePath) {
706+
final String startPath;
659707
if (NewPipeSettings.useStorageAccessFramework(context)) {
660-
StoredFileHelper.requestSafWithFileCreation(this, REQUEST_DOWNLOAD_SAVE_AS,
661-
filename, mime);
708+
startPath = null;
662709
} else {
663-
File initialSavePath;
710+
final File initialSavePath;
664711
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button) {
665712
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MUSIC);
666713
} else {
667714
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MOVIES);
668715
}
669-
670-
initialSavePath = new File(initialSavePath, filename);
671-
startActivityForResult(FilePickerActivityHelper.chooseFileToSave(context,
672-
initialSavePath.getAbsolutePath()), REQUEST_DOWNLOAD_SAVE_AS);
716+
startPath = initialSavePath.getAbsolutePath();
673717
}
674718

719+
startActivityForResult(StoredFileHelper.getNewPicker(context, startPath,
720+
filenameTmp), REQUEST_DOWNLOAD_SAVE_AS);
721+
675722
return;
676723
}
677724

678725
// check for existing file with the same name
679-
checkSelectedDownload(mainStorage, mainStorage.findFile(filename), filename, mime);
726+
checkSelectedDownload(mainStorage, mainStorage.findFile(filenameTmp), filenameTmp, mimeTmp);
680727

681728
// remember the last media type downloaded by the user
682-
prefs.edit()
683-
.putString(getString(R.string.last_used_download_type), selectedMediaType)
729+
prefs.edit().putString(getString(R.string.last_used_download_type), selectedMediaType)
684730
.apply();
685731
}
686732

app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import android.content.DialogInterface
77
import android.content.Intent
88
import android.content.IntentFilter
99
import android.content.res.Configuration
10+
import android.net.Uri
1011
import android.os.Bundle
11-
import android.os.Environment
1212
import android.os.Parcelable
1313
import android.view.LayoutInflater
1414
import android.view.Menu
@@ -52,7 +52,6 @@ import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem
5252
import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem.Companion.PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM
5353
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService
5454
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.EXPORT_COMPLETE_ACTION
55-
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.KEY_FILE_PATH
5655
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
5756
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.IMPORT_COMPLETE_ACTION
5857
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE
@@ -62,7 +61,7 @@ import org.schabi.newpipe.util.FilePickerActivityHelper
6261
import org.schabi.newpipe.util.NavigationHelper
6362
import org.schabi.newpipe.util.OnClickGesture
6463
import org.schabi.newpipe.util.ShareUtils
65-
import java.io.File
64+
import us.shandian.giga.io.StoredFileHelper
6665
import java.text.SimpleDateFormat
6766
import java.util.Date
6867
import java.util.Locale
@@ -188,15 +187,14 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
188187
}
189188

190189
private fun onImportPreviousSelected() {
191-
startActivityForResult(FilePickerActivityHelper.chooseSingleFile(activity), REQUEST_IMPORT_CODE)
190+
startActivityForResult(StoredFileHelper.getPicker(activity), REQUEST_IMPORT_CODE)
192191
}
193192

194193
private fun onExportSelected() {
195194
val date = SimpleDateFormat("yyyyMMddHHmm", Locale.ENGLISH).format(Date())
196195
val exportName = "newpipe_subscriptions_$date.json"
197-
val exportFile = File(Environment.getExternalStorageDirectory(), exportName)
198196

199-
startActivityForResult(FilePickerActivityHelper.chooseFileToSave(activity, exportFile.absolutePath), REQUEST_EXPORT_CODE)
197+
startActivityForResult(StoredFileHelper.getNewPicker(activity, null, exportName), REQUEST_EXPORT_CODE)
200198
}
201199

202200
private fun openReorderDialog() {
@@ -207,23 +205,20 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
207205
super.onActivityResult(requestCode, resultCode, data)
208206
if (data != null && data.data != null && resultCode == Activity.RESULT_OK) {
209207
if (requestCode == REQUEST_EXPORT_CODE) {
210-
val exportFile = Utils.getFileForUri(data.data!!)
211-
val parentFile = exportFile.parentFile!!
212-
if (!parentFile.canWrite() || !parentFile.canRead()) {
213-
Toast.makeText(activity, R.string.invalid_directory, Toast.LENGTH_SHORT).show()
214-
} else {
215-
activity.startService(
216-
Intent(activity, SubscriptionsExportService::class.java)
217-
.putExtra(KEY_FILE_PATH, exportFile.absolutePath)
218-
)
208+
var uri = data.data!!
209+
if (FilePickerActivityHelper.isOwnFileUri(activity, uri)) {
210+
uri = Uri.fromFile(Utils.getFileForUri(uri))
219211
}
212+
activity.startService(
213+
Intent(activity, SubscriptionsExportService::class.java)
214+
.putExtra(SubscriptionsExportService.KEY_FILE_PATH, uri)
215+
)
220216
} else if (requestCode == REQUEST_IMPORT_CODE) {
221-
val path = Utils.getFileForUri(data.data!!).absolutePath
222217
ImportConfirmationDialog.show(
223218
this,
224219
Intent(activity, SubscriptionsImportService::class.java)
225220
.putExtra(KEY_MODE, PREVIOUS_EXPORT_MODE)
226-
.putExtra(KEY_VALUE, path)
221+
.putExtra(KEY_VALUE, data.data)
227222
)
228223
}
229224
}

app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
import androidx.appcompat.app.ActionBar;
1919
import androidx.core.text.util.LinkifyCompat;
2020

21-
import com.nononsenseapps.filepicker.Utils;
22-
2321
import org.schabi.newpipe.BaseFragment;
2422
import org.schabi.newpipe.R;
2523
import org.schabi.newpipe.error.ErrorActivity;
@@ -30,13 +28,13 @@
3028
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
3129
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
3230
import org.schabi.newpipe.util.Constants;
33-
import org.schabi.newpipe.util.FilePickerActivityHelper;
3431
import org.schabi.newpipe.util.ServiceHelper;
3532

3633
import java.util.Collections;
3734
import java.util.List;
3835

3936
import icepick.State;
37+
import us.shandian.giga.io.StoredFileHelper;
4038

4139
import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.CHANNEL_URL;
4240
import static org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.CHANNEL_URL_MODE;
@@ -175,8 +173,7 @@ public void onImportUrl(final String value) {
175173
}
176174

177175
public void onImportFile() {
178-
startActivityForResult(FilePickerActivityHelper.chooseSingleFile(activity),
179-
REQUEST_IMPORT_FILE_CODE);
176+
startActivityForResult(StoredFileHelper.getPicker(activity), REQUEST_IMPORT_FILE_CODE);
180177
}
181178

182179
@Override
@@ -188,10 +185,10 @@ public void onActivityResult(final int requestCode, final int resultCode, final
188185

189186
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMPORT_FILE_CODE
190187
&& data.getData() != null) {
191-
final String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
192188
ImportConfirmationDialog.show(this,
193189
new Intent(activity, SubscriptionsImportService.class)
194-
.putExtra(KEY_MODE, INPUT_STREAM_MODE).putExtra(KEY_VALUE, path)
190+
.putExtra(KEY_MODE, INPUT_STREAM_MODE)
191+
.putExtra(KEY_VALUE, data.getData())
195192
.putExtra(Constants.KEY_SERVICE_ID, currentServiceId));
196193
}
197194
}

0 commit comments

Comments
 (0)