more SAF implementation

* full support for Directory API (Android Lollipop or later)
* best effort to handle any kind errors (missing file, revoked permissions, etc) and recover the download
* implemented directory choosing
* fix download database version upgrading
* misc. cleanup
* do not release permission on the old save path (if the user change the download directory) under SAF api
This commit is contained in:
kapodamy 2019-04-09 18:38:34 -03:00
parent 7ca7952790
commit 64626a7709
28 changed files with 946 additions and 589 deletions

View file

@ -41,7 +41,9 @@ import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.NavigationHelper;
import java.io.File;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
@ -346,7 +348,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
uri = FileProvider.getUriForFile(
mContext,
BuildConfig.APPLICATION_ID + ".provider",
mission.storage.getIOFile()
new File(URI.create(mission.storage.getUri().toString()))
);
} else {
uri = mission.storage.getUri();
@ -384,10 +386,18 @@ public class MissionAdapter extends Adapter<ViewHolder> {
}
private static String resolveMimeType(@NonNull Mission mission) {
String mimeType;
if (!mission.storage.isInvalid()) {
mimeType = mission.storage.getType();
if (mimeType != null && mimeType.length() > 0 && !mimeType.equals(StoredFileHelper.DEFAULT_MIME))
return mimeType;
}
String ext = Utility.getFileExt(mission.storage.getName());
if (ext == null) return DEFAULT_MIME_TYPE;
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1));
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1));
return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
}
@ -476,6 +486,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
return;
case ERROR_PROGRESS_LOST:
msg = R.string.error_progress_lost;
break;
default:
if (mission.errCode >= 100 && mission.errCode < 600) {
msgEx = "HTTP " + mission.errCode;
@ -554,7 +565,12 @@ public class MissionAdapter extends Adapter<ViewHolder> {
return true;
case R.id.retry:
if (mission.hasInvalidStorage()) {
mRecover.tryRecover(mission);
mDownloadManager.tryRecover(mission);
if (mission.storage.isInvalid())
mRecover.tryRecover(mission);
else
recoverMission(mission);
return true;
}
mission.psContinue(true);
@ -672,13 +688,12 @@ public class MissionAdapter extends Adapter<ViewHolder> {
if (mDeleter != null) mDeleter.resume();
}
public void recoverMission(DownloadMission mission, StoredFileHelper newStorage) {
public void recoverMission(DownloadMission mission) {
for (ViewHolderItem h : mPendingDownloadsItems) {
if (mission != h.item.mission) continue;
mission.changeStorage(newStorage);
mission.errCode = DownloadMission.ERROR_NOTHING;
mission.errObject = null;
mission.resetState(true, false, DownloadMission.ERROR_NOTHING);
h.status.setText(UNDEFINED_PROGRESS);
h.state = -1;
@ -822,9 +837,9 @@ public class MissionAdapter extends Adapter<ViewHolder> {
if (mission != null) {
if (mission.hasInvalidStorage()) {
retry.setEnabled(true);
delete.setEnabled(true);
showError.setEnabled(true);
retry.setVisible(true);
delete.setVisible(true);
showError.setVisible(true);
} else if (mission.isPsRunning()) {
switch (mission.errCode) {
case ERROR_INSUFFICIENT_STORAGE:

View file

@ -9,6 +9,7 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
@ -66,14 +67,7 @@ public class MissionsFragment extends Fragment {
mAdapter = new MissionAdapter(mContext, mBinder.getDownloadManager(), mEmpty);
mAdapter.deleterLoad(getView());
mAdapter.setRecover(mission ->
StoredFileHelper.requestSafWithFileCreation(
MissionsFragment.this,
REQUEST_DOWNLOAD_PATH_SAF,
mission.storage.getName(),
mission.storage.getType()
)
);
mAdapter.setRecover(MissionsFragment.this::recoverMission);
setAdapterButtons();
@ -92,7 +86,7 @@ public class MissionsFragment extends Fragment {
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.missions, container, false);
mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
@ -239,8 +233,18 @@ public class MissionsFragment extends Fragment {
mAdapter.setMasterButtons(mStart, mPause);
}
private void recoverMission(@NonNull DownloadMission mission) {
unsafeMissionTarget = mission;
StoredFileHelper.requestSafWithFileCreation(
MissionsFragment.this,
REQUEST_DOWNLOAD_PATH_SAF,
mission.storage.getName(),
mission.storage.getType()
);
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (mAdapter != null) {
@ -285,8 +289,9 @@ public class MissionsFragment extends Fragment {
}
try {
StoredFileHelper storage = new StoredFileHelper(mContext, data.getData(), unsafeMissionTarget.storage.getTag());
mAdapter.recoverMission(unsafeMissionTarget, storage);
String tag = unsafeMissionTarget.storage.getTag();
unsafeMissionTarget.storage = new StoredFileHelper(mContext, null, data.getData(), tag);
mAdapter.recoverMission(unsafeMissionTarget);
} catch (IOException e) {
Toast.makeText(mContext, R.string.general_error, Toast.LENGTH_LONG).show();
}