Fix files from SD card not being deleted (#48)

This commit is contained in:
Bart Uliasz 2021-09-18 05:29:42 -04:00 committed by GitHub
parent ac0ad8ec64
commit b977cde1af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 34 deletions

View file

@ -118,6 +118,7 @@
<activity android:name=".activities.DriveModeActivity" />
<activity android:name=".activities.PermissionActivity" />
<activity android:name=".activities.LockScreenActivity" />
<activity android:name=".activities.saf.SAFRequestActivity" />
<activity
android:name=".appshortcuts.AppShortcutLauncherActivity"

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021 Bartlomiej Uliasz.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package io.github.muntashirakon.music.activities.saf
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import io.github.muntashirakon.music.activities.saf.SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
import io.github.muntashirakon.music.util.SAFUtil
/** Created by buliasz on 2021-02-07. */
class SAFRequestActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this, SAFGuideActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SAF_GUIDE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
when (requestCode) {
REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this)
}
SAFUtil.REQUEST_SAF_PICK_TREE -> {
if (resultCode == RESULT_OK) {
SAFUtil.saveTreeUri(this, intent)
}
finish()
}
}
}
}

View file

@ -477,8 +477,7 @@ object MusicUtil : KoinComponent {
val id: Int = cursor.getInt(0)
val name: String = cursor.getString(1)
try { // File.delete can throw a security exception
val f = File(name)
if (f.delete()) {
if (SAFUtil.delete(context, name, null)) {
// Step 3: Remove selected track from the database
context.contentResolver.delete(
ContentUris.withAppendedId(
@ -488,8 +487,6 @@ object MusicUtil : KoinComponent {
)
deletedCount++
} else {
// I'm not sure if we'd ever get here (deletion would
// have to fail, but no exception thrown)
Log.e("MusicUtils", "Failed to delete file $name")
}
cursor.moveToNext()

View file

@ -14,6 +14,7 @@
package io.github.muntashirakon.music.util;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
@ -30,6 +31,7 @@ import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.Fragment;
import io.github.muntashirakon.music.R;
import io.github.muntashirakon.music.activities.saf.SAFRequestActivity;
import io.github.muntashirakon.music.model.Song;
import java.io.File;
import java.io.FileInputStream;
@ -50,7 +52,7 @@ public class SAFUtil {
public static final int REQUEST_SAF_PICK_TREE = 43;
public static boolean isSAFRequired(File file) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !file.canWrite();
return !file.canWrite();
}
public static boolean isSAFRequired(String path) {
@ -114,21 +116,21 @@ public class SAFUtil {
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void saveTreeUri(Context context, Intent data) {
Uri uri = data.getData();
context
.getContentResolver()
.takePersistableUriPermission(
uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
PreferenceUtil.INSTANCE.setSafSdCardUri(uri.toString());
if (uri != null) {
context.getContentResolver().takePersistableUriPermission(
uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
PreferenceUtil.INSTANCE.setSafSdCardUri(uri.toString());
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static boolean isTreeUriSaved(Context context) {
public static boolean isTreeUriSaved() {
return !TextUtils.isEmpty(PreferenceUtil.INSTANCE.getSafSdCardUri());
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static boolean isSDCardAccessGranted(Context context) {
if (!isTreeUriSaved(context)) return false;
if (!isTreeUriSaved()) return false;
String sdcardUri = PreferenceUtil.INSTANCE.getSafSdCardUri();
@ -152,6 +154,10 @@ public class SAFUtil {
*/
@Nullable
public static Uri findDocument(DocumentFile dir, List<String> segments) {
if (dir == null) {
return null;
}
for (DocumentFile file : dir.listFiles()) {
int index = segments.indexOf(file.getName());
if (index == -1) {
@ -196,7 +202,7 @@ public class SAFUtil {
return;
}
if (isTreeUriSaved(context)) {
if (isTreeUriSaved()) {
List<String> pathSegments =
new ArrayList<>(Arrays.asList(audio.getFile().getAbsolutePath().split("/")));
Uri sdcard = Uri.parse(PreferenceUtil.INSTANCE.getSafSdCardUri());
@ -235,6 +241,7 @@ public class SAFUtil {
fos.write(audioContent);
fos.close();
//noinspection ResultOfMethodCallIgnored
temp.delete();
} catch (final Exception e) {
Log.e(TAG, "writeSAF: Failed to write to file descriptor provided by SAF", e);
@ -245,58 +252,57 @@ public class SAFUtil {
}
}
public static void delete(Context context, String path, Uri safUri) {
public static boolean delete(Context context, String path, Uri safUri) {
if (isSAFRequired(path)) {
deleteSAF(context, path, safUri);
return deleteUsingSAF(context, path, safUri);
} else {
try {
deleteFile(path);
return new File(path).delete();
} catch (NullPointerException e) {
Log.e("MusicUtils", "Failed to find file " + path);
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
public static void deleteFile(String path) {
new File(path).delete();
}
@SuppressLint("StringFormatInvalid")
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void deleteSAF(Context context, String path, Uri safUri) {
Uri uri = null;
private static boolean deleteUsingSAF(Context context, String path, Uri safUri) {
if (context == null) {
Log.e(TAG, "deleteSAF: context == null");
return;
return false;
}
if (isTreeUriSaved(context)) {
if (safUri == null && isTreeUriSaved()) {
List<String> pathSegments = new ArrayList<>(Arrays.asList(path.split("/")));
Uri sdcard = Uri.parse(PreferenceUtil.INSTANCE.getSafSdCardUri());
uri = findDocument(DocumentFile.fromTreeUri(context, sdcard), pathSegments);
safUri = findDocument(DocumentFile.fromTreeUri(context, sdcard), pathSegments);
}
if (uri == null) {
uri = safUri;
}
if (uri == null) {
Log.e(TAG, "deleteSAF: Can't get SAF URI");
if (safUri == null) {
requestSAF(context);
toast(context, context.getString(R.string.saf_error_uri));
return;
return false;
}
try {
DocumentsContract.deleteDocument(context.getContentResolver(), uri);
DocumentsContract.deleteDocument(context.getContentResolver(), safUri);
} catch (final Exception e) {
Log.e(TAG, "deleteSAF: Failed to delete a file descriptor provided by SAF", e);
toast(
context,
String.format(context.getString(R.string.saf_delete_failed), e.getLocalizedMessage()));
return false;
}
return true;
}
private static void requestSAF(Context context) {
Intent intent = new Intent(context, SAFRequestActivity.class);
context.startActivity(intent);
}
private static void toast(final Context context, final String message) {