From 72db30128c8f8f149d2727c8f439af5969c58a99 Mon Sep 17 00:00:00 2001 From: cwyc Date: Sun, 28 Jan 2024 18:00:14 -0500 Subject: [PATCH] Android: Improvements to DocumentProvider Added move and rename methods Provider notifies viewer to refresh view when files are changed Bumped up TargetApi annotation for DocumentsContract.buildTreeDocumentUri. Could alternatively use androidx compat class. --- .../provider/RetroDocumentsProvider.java | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java index c49a7432ff..4d2f927835 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/provider/RetroDocumentsProvider.java @@ -11,6 +11,7 @@ import android.graphics.Point; import android.os.Build; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; +import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; @@ -35,11 +36,13 @@ import java.util.LinkedList; * offering two different ways of accessing your stored data. This would be confusing for users." * - http://developer.android.com/guide/topics/providers/document-provider.html#43 */ -@TargetApi(Build.VERSION_CODES.KITKAT) +@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class RetroDocumentsProvider extends DocumentsProvider { private static final String ALL_MIME_TYPES = "*/*"; + private String DOCUMENTS_AUTHORITY; + // The default columns to return information about a root if no specific // columns are requested in a query. private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{ @@ -89,6 +92,36 @@ public class RetroDocumentsProvider extends DocumentsProvider { return result; } + @Override + public String moveDocument(String sourceDocumentId, String sourceParentDocumentId, String targetParentDocumentId) throws FileNotFoundException { + File sourceFile = getFileForDocId(sourceDocumentId); + File targetParentFile = getFileForDocId(targetParentDocumentId); + File destination = new File(targetParentFile, sourceFile.getName()); + + boolean success = sourceFile.renameTo(destination); + if(!success){ + throw new FileNotFoundException("Failed to move file " + sourceDocumentId + " to " + targetParentDocumentId); + } + + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, sourceParentDocumentId), null); + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, targetParentDocumentId), null); + return getDocIdForFile(destination); + } + + @Override + public String renameDocument(String documentId, String displayName) throws FileNotFoundException{ + File document = getFileForDocId(documentId); + File destination = new File(document.getParentFile(), displayName); + + boolean success = document.renameTo(destination); + if(!success){ + throw new FileNotFoundException("Failed to rename file " + documentId + " to " + displayName); + } + + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, getDocIdForFile(document.getParentFile())), null); + return getDocIdForFile(destination); + } + @Override public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION); @@ -96,6 +129,7 @@ public class RetroDocumentsProvider extends DocumentsProvider { for (File file : parent.listFiles()) { includeFile(result, null, file); } + result.setNotificationUri(getContext().getContentResolver(), DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, parentDocumentId)); return result; } @@ -115,6 +149,7 @@ public class RetroDocumentsProvider extends DocumentsProvider { @Override public boolean onCreate() { + DOCUMENTS_AUTHORITY = getContext().getPackageName() + ".documents"; return true; } @@ -138,14 +173,25 @@ public class RetroDocumentsProvider extends DocumentsProvider { } catch (IOException e) { throw new FileNotFoundException("Failed to create document with id " + newFile.getPath()); } + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, parentDocumentId), null); return newFile.getPath(); } @Override public void deleteDocument(String documentId) throws FileNotFoundException { File file = getFileForDocId(documentId); - if (!file.delete()) { - throw new FileNotFoundException("Failed to delete document with id " + documentId); + rm_r(file); + getContext().getContentResolver().notifyChange(DocumentsContract.buildTreeDocumentUri(DOCUMENTS_AUTHORITY, getDocIdForFile(file.getParentFile())), null); + } + + void rm_r (File file) throws FileNotFoundException{ + if(file.isDirectory()){ + for(File child : file.listFiles()) { + rm_r(child); + } + } + if(!file.delete()){ + throw new FileNotFoundException("Could not delete file " + file.getPath()); } } @@ -248,11 +294,11 @@ public class RetroDocumentsProvider extends DocumentsProvider { int flags = 0; if (file.isDirectory()) { - if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE; - } else if (file.canWrite()) { - flags |= Document.FLAG_SUPPORTS_WRITE; + if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE | Document.FLAG_SUPPORTS_RENAME; + } else { + if (file.canWrite()) flags |= Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_RENAME; } - if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE; + if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_MOVE; final String displayName = file.getName(); final String mimeType = getMimeType(file);