Merge pull request #2521 from kapodamy/saf-workarround
Downloads: add switch for saf/legacy file picker
This commit is contained in:
commit
96baa2978d
|
@ -60,6 +60,7 @@ import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
import org.schabi.newpipe.util.KioskTranslator;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
import org.schabi.newpipe.util.ServiceHelper;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
@ -421,6 +422,17 @@ public class MainActivity extends AppCompatActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
switch (requestCode) {
|
||||||
|
case PermissionHelper.DOWNLOADS_REQUEST_CODE:
|
||||||
|
NavigationHelper.openDownloads(this);
|
||||||
|
break;
|
||||||
|
case PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE:
|
||||||
|
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
|
||||||
|
if (fragment instanceof VideoDetailFragment) {
|
||||||
|
((VideoDetailFragment) fragment).openDownloadDialog();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -74,10 +74,13 @@ import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
|
||||||
*/
|
*/
|
||||||
public class RouterActivity extends AppCompatActivity {
|
public class RouterActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@State protected int currentServiceId = -1;
|
@State
|
||||||
|
protected int currentServiceId = -1;
|
||||||
private StreamingService currentService;
|
private StreamingService currentService;
|
||||||
@State protected LinkType currentLinkType;
|
@State
|
||||||
@State protected int selectedRadioPosition = -1;
|
protected LinkType currentLinkType;
|
||||||
|
@State
|
||||||
|
protected int selectedRadioPosition = -1;
|
||||||
protected int selectedPreviously = -1;
|
protected int selectedPreviously = -1;
|
||||||
|
|
||||||
protected String currentUrl;
|
protected String currentUrl;
|
||||||
|
@ -257,7 +260,7 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
|
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
|
||||||
.setPositiveButton(R.string.always, dialogButtonsClickListener)
|
.setPositiveButton(R.string.always, dialogButtonsClickListener)
|
||||||
.setOnDismissListener((dialog) -> {
|
.setOnDismissListener((dialog) -> {
|
||||||
if(!selectionIsDownload) finish();
|
if (!selectionIsDownload) finish();
|
||||||
})
|
})
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
|
@ -358,13 +361,13 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
positiveButton.setEnabled(state);
|
positiveButton.setEnabled(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleText(){
|
private void handleText() {
|
||||||
String searchString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
String searchString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||||
int serviceId = getIntent().getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
int serviceId = getIntent().getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
Intent intent = new Intent(getThemeWrapperContext(), MainActivity.class);
|
Intent intent = new Intent(getThemeWrapperContext(), MainActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
NavigationHelper.openSearch(getThemeWrapperContext(),serviceId,searchString);
|
NavigationHelper.openSearch(getThemeWrapperContext(), serviceId, searchString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleChoice(final String selectedChoiceKey) {
|
private void handleChoice(final String selectedChoiceKey) {
|
||||||
|
@ -382,8 +385,10 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedChoiceKey.equals(getString(R.string.download_key))) {
|
if (selectedChoiceKey.equals(getString(R.string.download_key))) {
|
||||||
selectionIsDownload = true;
|
if (PermissionHelper.checkStoragePermissions(this, PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
||||||
openDownloadDialog();
|
selectionIsDownload = true;
|
||||||
|
openDownloadDialog();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +400,7 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(intent -> {
|
.subscribe(intent -> {
|
||||||
if(!internalRoute){
|
if (!internalRoute) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
}
|
}
|
||||||
|
@ -445,17 +450,21 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
for (int i: grantResults){
|
for (int i : grantResults) {
|
||||||
if (i == PackageManager.PERMISSION_DENIED){
|
if (i == PackageManager.PERMISSION_DENIED) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (requestCode == PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE) {
|
||||||
|
openDownloadDialog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AdapterChoiceItem {
|
private static class AdapterChoiceItem {
|
||||||
final String description, key;
|
final String description, key;
|
||||||
@DrawableRes final int icon;
|
@DrawableRes
|
||||||
|
final int icon;
|
||||||
|
|
||||||
AdapterChoiceItem(String key, String description, int icon) {
|
AdapterChoiceItem(String key, String description, int icon) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
@ -553,7 +562,8 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
|
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
|
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
|
||||||
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);;
|
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
|
||||||
|
;
|
||||||
|
|
||||||
PlayQueue playQueue;
|
PlayQueue playQueue;
|
||||||
String playerChoice = choice.playerChoice;
|
String playerChoice = choice.playerChoice;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.content.ServiceConnection;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.IdRes;
|
import android.support.annotation.IdRes;
|
||||||
|
@ -33,6 +34,8 @@ import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.nononsenseapps.filepicker.Utils;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
|
@ -45,13 +48,17 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.extractor.utils.Localization;
|
import org.schabi.newpipe.extractor.utils.Localization;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
|
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;
|
||||||
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.SecondaryStreamHelper;
|
import org.schabi.newpipe.util.SecondaryStreamHelper;
|
||||||
import org.schabi.newpipe.util.StreamItemAdapter;
|
import org.schabi.newpipe.util.StreamItemAdapter;
|
||||||
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -72,7 +79,7 @@ import us.shandian.giga.service.MissionState;
|
||||||
public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
||||||
private static final String TAG = "DialogFragment";
|
private static final String TAG = "DialogFragment";
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
private static final int REQUEST_DOWNLOAD_PATH_SAF = 0x1230;
|
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected StreamInfo currentInfo;
|
protected StreamInfo currentInfo;
|
||||||
|
@ -173,6 +180,11 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
||||||
|
|
||||||
|
if (!PermissionHelper.checkStoragePermissions(getActivity(), PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
||||||
|
getDialog().dismiss();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context = getContext();
|
context = getContext();
|
||||||
|
|
||||||
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
||||||
|
@ -311,12 +323,18 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
if (requestCode == REQUEST_DOWNLOAD_PATH_SAF && resultCode == Activity.RESULT_OK) {
|
if (requestCode == REQUEST_DOWNLOAD_SAVE_AS && resultCode == Activity.RESULT_OK) {
|
||||||
if (data.getData() == null) {
|
if (data.getData() == null) {
|
||||||
showFailedDialog(R.string.general_error);
|
showFailedDialog(R.string.general_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
|
||||||
|
File file = Utils.getFileForUri(data.getData());
|
||||||
|
checkSelectedDownload(null, Uri.fromFile(file), file.getName(), StoredFileHelper.DEFAULT_MIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
showFailedDialog(R.string.general_error);
|
showFailedDialog(R.string.general_error);
|
||||||
|
@ -569,12 +587,27 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
// This part is called if with SAF preferred:
|
// This part is called if with SAF preferred:
|
||||||
// * older android version running
|
// * older android version running
|
||||||
// * save path not defined (via download settings)
|
// * save path not defined (via download settings)
|
||||||
// * the user as checked the "ask where to download" option
|
// * the user checked the "ask where to download" option
|
||||||
|
|
||||||
if (!askForSavePath)
|
if (!askForSavePath)
|
||||||
Toast.makeText(context, getString(R.string.no_available_dir), Toast.LENGTH_LONG).show();
|
Toast.makeText(context, getString(R.string.no_available_dir), Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
StoredFileHelper.requestSafWithFileCreation(this, REQUEST_DOWNLOAD_PATH_SAF, filename, mime);
|
if (NewPipeSettings.useStorageAccessFramework(context)) {
|
||||||
|
StoredFileHelper.requestSafWithFileCreation(this, REQUEST_DOWNLOAD_SAVE_AS, filename, mime);
|
||||||
|
} else {
|
||||||
|
File initialSavePath;
|
||||||
|
if (radioStreamsGroup.getCheckedRadioButtonId() == R.id.audio_button)
|
||||||
|
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MUSIC);
|
||||||
|
else
|
||||||
|
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MOVIES);
|
||||||
|
|
||||||
|
initialSavePath = new File(initialSavePath, filename);
|
||||||
|
startActivityForResult(
|
||||||
|
FilePickerActivityHelper.chooseFileToSave(context, initialSavePath.getAbsolutePath()),
|
||||||
|
REQUEST_DOWNLOAD_SAVE_AS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,6 +657,11 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
// This part is called if:
|
// This part is called if:
|
||||||
// * using SAF on older android version
|
// * using SAF on older android version
|
||||||
// * save path not defined
|
// * save path not defined
|
||||||
|
// * if the file exists overwrite it, is not necessary ask
|
||||||
|
if (!storage.existsAsFile() && !storage.create()) {
|
||||||
|
showFailedDialog(R.string.error_file_creation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
continueSelectedDownload(storage);
|
continueSelectedDownload(storage);
|
||||||
return;
|
return;
|
||||||
} else if (targetFile == null) {
|
} else if (targetFile == null) {
|
||||||
|
@ -728,7 +766,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
try {
|
try {
|
||||||
if (storage.length() > 0) storage.truncate();
|
if (storage.length() > 0) storage.truncate();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "failed to overwrite the file: " + storage.getUri().toString(), e);
|
Log.e(TAG, "failed to truncate the file: " + storage.getUri().toString(), e);
|
||||||
showFailedDialog(R.string.overwrite_failed);
|
showFailedDialog(R.string.overwrite_failed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,7 +384,10 @@ public class VideoDetailFragment
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.detail_controls_download:
|
case R.id.detail_controls_download:
|
||||||
this.openDownloadDialog();
|
if (PermissionHelper.checkStoragePermissions(activity,
|
||||||
|
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
||||||
|
this.openDownloadDialog();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.detail_uploader_root_layout:
|
case R.id.detail_uploader_root_layout:
|
||||||
if (TextUtils.isEmpty(currentInfo.getUploaderUrl())) {
|
if (TextUtils.isEmpty(currentInfo.getUploaderUrl())) {
|
||||||
|
|
|
@ -35,8 +35,6 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
private String DOWNLOAD_PATH_VIDEO_PREFERENCE;
|
private String DOWNLOAD_PATH_VIDEO_PREFERENCE;
|
||||||
private String DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
private String DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
||||||
|
|
||||||
private String DOWNLOAD_STORAGE_ASK;
|
|
||||||
|
|
||||||
private Preference prefPathVideo;
|
private Preference prefPathVideo;
|
||||||
private Preference prefPathAudio;
|
private Preference prefPathAudio;
|
||||||
private Preference prefStorageAsk;
|
private Preference prefStorageAsk;
|
||||||
|
@ -49,14 +47,14 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
|
|
||||||
DOWNLOAD_PATH_VIDEO_PREFERENCE = getString(R.string.download_path_video_key);
|
DOWNLOAD_PATH_VIDEO_PREFERENCE = getString(R.string.download_path_video_key);
|
||||||
DOWNLOAD_PATH_AUDIO_PREFERENCE = getString(R.string.download_path_audio_key);
|
DOWNLOAD_PATH_AUDIO_PREFERENCE = getString(R.string.download_path_audio_key);
|
||||||
DOWNLOAD_STORAGE_ASK = getString(R.string.downloads_storage_ask);
|
final String downloadStorageAsk = getString(R.string.downloads_storage_ask);
|
||||||
|
|
||||||
prefPathVideo = findPreference(DOWNLOAD_PATH_VIDEO_PREFERENCE);
|
prefPathVideo = findPreference(DOWNLOAD_PATH_VIDEO_PREFERENCE);
|
||||||
prefPathAudio = findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
|
prefPathAudio = findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
|
||||||
prefStorageAsk = findPreference(DOWNLOAD_STORAGE_ASK);
|
prefStorageAsk = findPreference(downloadStorageAsk);
|
||||||
|
|
||||||
updatePreferencesSummary();
|
updatePreferencesSummary();
|
||||||
updatePathPickers(!defaultPreferences.getBoolean(DOWNLOAD_STORAGE_ASK, false));
|
updatePathPickers(!defaultPreferences.getBoolean(downloadStorageAsk, false));
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
prefStorageAsk.setSummary(R.string.downloads_storage_ask_summary);
|
prefStorageAsk.setSummary(R.string.downloads_storage_ask_summary);
|
||||||
|
@ -180,7 +178,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent i;
|
Intent i;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && NewPipeSettings.useStorageAccessFramework(ctx)) {
|
||||||
i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
.putExtra("android.content.extra.SHOW_ADVANCED", true)
|
.putExtra("android.content.extra.SHOW_ADVANCED", true)
|
||||||
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | StoredDirectoryHelper.PERMISSION_FLAGS);
|
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
|
@ -221,16 +219,17 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
// steps:
|
|
||||||
// 1. revoke permissions on the old save path
|
|
||||||
// 2. acquire permissions on the new save path
|
|
||||||
// 3. save the new path, if step(2) was successful
|
|
||||||
final Context ctx = getContext();
|
|
||||||
if (ctx == null) throw new NullPointerException("getContext()");
|
|
||||||
|
|
||||||
forgetSAFTree(ctx, defaultPreferences.getString(key, ""));
|
// revoke permissions on the old save path (required for SAF only)
|
||||||
|
final Context ctx = getContext();
|
||||||
|
if (ctx == null) throw new NullPointerException("getContext()");
|
||||||
|
|
||||||
|
forgetSAFTree(ctx, defaultPreferences.getString(key, ""));
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !FilePickerActivityHelper.isOwnFileUri(ctx, uri)) {
|
||||||
|
// steps to acquire the selected path:
|
||||||
|
// 1. acquire permissions on the new save path
|
||||||
|
// 2. save the new path, if step(2) was successful
|
||||||
try {
|
try {
|
||||||
ctx.grantUriPermission(ctx.getPackageName(), uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
ctx.grantUriPermission(ctx.getPackageName(), uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
|
|
||||||
|
@ -245,7 +244,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
File target = Utils.getFileForUri(data.getData());
|
File target = Utils.getFileForUri(uri);
|
||||||
if (!target.canWrite()) {
|
if (!target.canWrite()) {
|
||||||
showMessageDialog(R.string.download_to_sdcard_error_title, R.string.download_to_sdcard_error_message);
|
showMessageDialog(R.string.download_to_sdcard_error_title, R.string.download_to_sdcard_error_message);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -22,7 +22,6 @@ package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -67,10 +66,8 @@ public class NewPipeSettings {
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.video_audio_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.video_audio_settings, true);
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.debug_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.debug_settings, true);
|
||||||
|
|
||||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
getVideoDownloadFolder(context);
|
||||||
getVideoDownloadFolder(context);
|
getAudioDownloadFolder(context);
|
||||||
getAudioDownloadFolder(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void getVideoDownloadFolder(Context context) {
|
private static void getVideoDownloadFolder(Context context) {
|
||||||
|
@ -93,11 +90,19 @@ public class NewPipeSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static File getDir(String defaultDirectoryName) {
|
public static File getDir(String defaultDirectoryName) {
|
||||||
return new File(Environment.getExternalStorageDirectory(), defaultDirectoryName);
|
return new File(Environment.getExternalStorageDirectory(), defaultDirectoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getNewPipeChildFolderPathForDir(File dir) {
|
private static String getNewPipeChildFolderPathForDir(File dir) {
|
||||||
return new File(dir, "NewPipe").toURI().toString();
|
return new File(dir, "NewPipe").toURI().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean useStorageAccessFramework(Context context) {
|
||||||
|
final String key = context.getString(R.string.storage_use_saf);
|
||||||
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
return prefs.getBoolean(key, false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.schabi.newpipe.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -29,7 +30,7 @@ public class FilePickerActivityHelper extends com.nononsenseapps.filepicker.File
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
if(ThemeHelper.isLightThemeSelected(this)) {
|
if (ThemeHelper.isLightThemeSelected(this)) {
|
||||||
this.setTheme(R.style.FilePickerThemeLight);
|
this.setTheme(R.style.FilePickerThemeLight);
|
||||||
} else {
|
} else {
|
||||||
this.setTheme(R.style.FilePickerThemeDark);
|
this.setTheme(R.style.FilePickerThemeDark);
|
||||||
|
@ -73,6 +74,11 @@ public class FilePickerActivityHelper extends com.nononsenseapps.filepicker.File
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE, FilePickerActivityHelper.MODE_NEW_FILE);
|
.putExtra(FilePickerActivityHelper.EXTRA_MODE, FilePickerActivityHelper.MODE_NEW_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isOwnFileUri(@NonNull Context context, @NonNull Uri uri) {
|
||||||
|
if (uri.getAuthority() == null) return false;
|
||||||
|
return uri.getAuthority().startsWith(context.getPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Internal
|
// Internal
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -446,6 +446,9 @@ public class NavigationHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean openDownloads(Activity activity) {
|
public static boolean openDownloads(Activity activity) {
|
||||||
|
if (!PermissionHelper.checkStoragePermissions(activity, PermissionHelper.DOWNLOADS_REQUEST_CODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Intent intent = new Intent(activity, DownloadActivity.class);
|
Intent intent = new Intent(activity, DownloadActivity.class);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -18,10 +18,12 @@ import android.widget.Toast;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
public class PermissionHelper {
|
public class PermissionHelper {
|
||||||
|
public static final int DOWNLOAD_DIALOG_REQUEST_CODE = 778;
|
||||||
|
public static final int DOWNLOADS_REQUEST_CODE = 777;
|
||||||
|
|
||||||
public static boolean checkStoragePermissions(Activity activity, int requestCode) {
|
public static boolean checkStoragePermissions(Activity activity, int requestCode) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
if(!checkReadStoragePermissions(activity, requestCode)) return false;
|
if (!checkReadStoragePermissions(activity, requestCode)) return false;
|
||||||
}
|
}
|
||||||
return checkWriteStoragePermissions(activity, requestCode);
|
return checkWriteStoragePermissions(activity, requestCode);
|
||||||
}
|
}
|
||||||
|
@ -89,7 +91,7 @@ public class PermissionHelper {
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
context.startActivity(i);
|
context.startActivity(i);
|
||||||
return false;
|
return false;
|
||||||
}else return true;
|
} else return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPopupEnabled(Context context) {
|
public static boolean isPopupEnabled(Context context) {
|
||||||
|
|
|
@ -35,8 +35,8 @@ public class DownloadManager {
|
||||||
public final static int SPECIAL_PENDING = 1;
|
public final static int SPECIAL_PENDING = 1;
|
||||||
public final static int SPECIAL_FINISHED = 2;
|
public final static int SPECIAL_FINISHED = 2;
|
||||||
|
|
||||||
static final String TAG_AUDIO = "audio";
|
public static final String TAG_AUDIO = "audio";
|
||||||
static final String TAG_VIDEO = "video";
|
public static final String TAG_VIDEO = "video";
|
||||||
|
|
||||||
private final FinishedMissionStore mFinishedMissionStore;
|
private final FinishedMissionStore mFinishedMissionStore;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -22,9 +24,14 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.nononsenseapps.filepicker.Utils;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
|
@ -37,7 +44,7 @@ import us.shandian.giga.ui.adapter.MissionAdapter;
|
||||||
public class MissionsFragment extends Fragment {
|
public class MissionsFragment extends Fragment {
|
||||||
|
|
||||||
private static final int SPAN_SIZE = 2;
|
private static final int SPAN_SIZE = 2;
|
||||||
private static final int REQUEST_DOWNLOAD_PATH_SAF = 0x1230;
|
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
|
||||||
|
|
||||||
private SharedPreferences mPrefs;
|
private SharedPreferences mPrefs;
|
||||||
private boolean mLinear;
|
private boolean mLinear;
|
||||||
|
@ -242,12 +249,28 @@ public class MissionsFragment extends Fragment {
|
||||||
|
|
||||||
private void recoverMission(@NonNull DownloadMission mission) {
|
private void recoverMission(@NonNull DownloadMission mission) {
|
||||||
unsafeMissionTarget = mission;
|
unsafeMissionTarget = mission;
|
||||||
StoredFileHelper.requestSafWithFileCreation(
|
|
||||||
MissionsFragment.this,
|
if (NewPipeSettings.useStorageAccessFramework(mContext)) {
|
||||||
REQUEST_DOWNLOAD_PATH_SAF,
|
StoredFileHelper.requestSafWithFileCreation(
|
||||||
mission.storage.getName(),
|
MissionsFragment.this,
|
||||||
mission.storage.getType()
|
REQUEST_DOWNLOAD_SAVE_AS,
|
||||||
);
|
mission.storage.getName(),
|
||||||
|
mission.storage.getType()
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
File initialSavePath;
|
||||||
|
if (DownloadManager.TAG_VIDEO.equals(mission.storage.getType()))
|
||||||
|
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MOVIES);
|
||||||
|
else
|
||||||
|
initialSavePath = NewPipeSettings.getDir(Environment.DIRECTORY_MUSIC);
|
||||||
|
|
||||||
|
initialSavePath = new File(initialSavePath, mission.storage.getName());
|
||||||
|
startActivityForResult(
|
||||||
|
FilePickerActivityHelper.chooseFileToSave(mContext, initialSavePath.getAbsolutePath()),
|
||||||
|
REQUEST_DOWNLOAD_SAVE_AS
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -290,15 +313,20 @@ public class MissionsFragment extends Fragment {
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
if (requestCode != REQUEST_DOWNLOAD_PATH_SAF || resultCode != Activity.RESULT_OK) return;
|
if (requestCode != REQUEST_DOWNLOAD_SAVE_AS || resultCode != Activity.RESULT_OK) return;
|
||||||
|
|
||||||
if (unsafeMissionTarget == null || data.getData() == null) {
|
if (unsafeMissionTarget == null || data.getData() == null) {
|
||||||
return;// unsafeMissionTarget cannot be null
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Uri fileUri = data.getData();
|
||||||
|
if (fileUri.getAuthority() != null && FilePickerActivityHelper.isOwnFileUri(mContext, fileUri)) {
|
||||||
|
fileUri = Uri.fromFile(Utils.getFileForUri(fileUri));
|
||||||
|
}
|
||||||
|
|
||||||
String tag = unsafeMissionTarget.storage.getTag();
|
String tag = unsafeMissionTarget.storage.getTag();
|
||||||
unsafeMissionTarget.storage = new StoredFileHelper(mContext, null, data.getData(), tag);
|
unsafeMissionTarget.storage = new StoredFileHelper(mContext, null, fileUri, tag);
|
||||||
mAdapter.recoverMission(unsafeMissionTarget);
|
mAdapter.recoverMission(unsafeMissionTarget);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Toast.makeText(mContext, R.string.general_error, Toast.LENGTH_LONG).show();
|
Toast.makeText(mContext, R.string.general_error, Toast.LENGTH_LONG).show();
|
||||||
|
|
|
@ -458,7 +458,9 @@ abrir en modo popup</string>
|
||||||
|
|
||||||
<string name="downloads_storage_ask_title">Preguntar dónde descargar</string>
|
<string name="downloads_storage_ask_title">Preguntar dónde descargar</string>
|
||||||
<string name="downloads_storage_ask_summary">Se preguntará dónde guardar cada descarga</string>
|
<string name="downloads_storage_ask_summary">Se preguntará dónde guardar cada descarga</string>
|
||||||
<string name="downloads_storage_ask_summary_kitkat">Se preguntará dónde guardar cada descarga.\nHabilita esta opción si quieres descargar en la tarjeta SD externa</string>
|
<string name="downloads_storage_ask_summary_kitkat">Se preguntará dónde guardar cada descarga.\nHabilita esta opción junto con SAF si quieres descargar en la tarjeta SD externa</string>
|
||||||
|
<string name="downloads_storage_use_saf_title">Usar SAF</string>
|
||||||
|
<string name="downloads_storage_use_saf_summary">El Framework de Acceso al Almacenamiento permite descargar en la tarjeta SD externa.\nNota: Algunos los dispositivos no son compatibles</string>
|
||||||
|
|
||||||
<string name="unsubscribe">Desuscribirse</string>
|
<string name="unsubscribe">Desuscribirse</string>
|
||||||
<string name="tab_new">Nueva pestaña</string>
|
<string name="tab_new">Nueva pestaña</string>
|
||||||
|
|
|
@ -163,6 +163,7 @@
|
||||||
<string name="clear_search_history_key" translatable="false">clear_search_history</string>
|
<string name="clear_search_history_key" translatable="false">clear_search_history</string>
|
||||||
|
|
||||||
<string name="downloads_storage_ask" translatable="false">downloads_storage_ask</string>
|
<string name="downloads_storage_ask" translatable="false">downloads_storage_ask</string>
|
||||||
|
<string name="storage_use_saf" translatable="false">storage_use_saf</string>
|
||||||
|
|
||||||
<!-- FileName Downloads -->
|
<!-- FileName Downloads -->
|
||||||
<string name="settings_file_charset_key" translatable="false">file_rename_charset</string>
|
<string name="settings_file_charset_key" translatable="false">file_rename_charset</string>
|
||||||
|
|
|
@ -556,6 +556,8 @@
|
||||||
|
|
||||||
<string name="downloads_storage_ask_title">Ask where to download</string>
|
<string name="downloads_storage_ask_title">Ask where to download</string>
|
||||||
<string name="downloads_storage_ask_summary">You will be asked where to save each download</string>
|
<string name="downloads_storage_ask_summary">You will be asked where to save each download</string>
|
||||||
<string name="downloads_storage_ask_summary_kitkat">You will be asked where to save each download.\nEnable this option if you want download to the external SD Card</string>
|
<string name="downloads_storage_ask_summary_kitkat">You will be asked where to save each download.\nEnable this option with SAF if you want download to the external SD Card</string>
|
||||||
|
<string name="downloads_storage_use_saf_title">Use SAF</string>
|
||||||
|
<string name="downloads_storage_use_saf_summary">The Storage Access Framework allow download to the external SD Card.\nNote: some devices are not compatible</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -12,6 +12,13 @@
|
||||||
android:summary="@string/downloads_storage_ask_summary_kitkat"
|
android:summary="@string/downloads_storage_ask_summary_kitkat"
|
||||||
android:title="@string/downloads_storage_ask_title" />
|
android:title="@string/downloads_storage_ask_title" />
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/storage_use_saf"
|
||||||
|
android:summary="@string/downloads_storage_use_saf_summary"
|
||||||
|
android:title="@string/downloads_storage_use_saf_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
android:dialogTitle="@string/download_path_dialog_title"
|
android:dialogTitle="@string/download_path_dialog_title"
|
||||||
|
|
Loading…
Reference in New Issue