1010import android .graphics .Point ;
1111import android .os .Build ;
1212import android .os .CancellationSignal ;
13+ import android .os .Environment ;
1314import android .os .ParcelFileDescriptor ;
15+ import android .provider .DocumentsContract ;
1416import android .provider .DocumentsContract .Document ;
1517import android .provider .DocumentsContract .Root ;
1618import android .provider .DocumentsProvider ;
1719import android .webkit .MimeTypeMap ;
1820
21+ import com .retroarch .BuildConfig ;
1922import com .retroarch .R ;
2023
2124import java .io .File ;
3538 * offering two different ways of accessing your stored data. This would be confusing for users."
3639 * - http://developer.android.com/guide/topics/providers/document-provider.html#43
3740 */
38- @ TargetApi (Build .VERSION_CODES .KITKAT )
41+ @ TargetApi (Build .VERSION_CODES .LOLLIPOP )
3942public class RetroDocumentsProvider extends DocumentsProvider {
4043
4144 private static final String ALL_MIME_TYPES = "*/*" ;
4245
46+ private String DOCUMENTS_AUTHORITY ;
47+
4348 // The default columns to return information about a root if no specific
4449 // columns are requested in a query.
4550 private static final String [] DEFAULT_ROOT_PROJECTION = new String []{
@@ -66,19 +71,44 @@ public class RetroDocumentsProvider extends DocumentsProvider {
6671
6772 @ Override
6873 public Cursor queryRoots (String [] projection ) throws FileNotFoundException {
69- final File BASE_DIR = new File (getContext ().getFilesDir ().getParent ());
7074 final MatrixCursor result = new MatrixCursor (projection != null ? projection : DEFAULT_ROOT_PROJECTION );
7175 @ SuppressWarnings ("ConstantConditions" ) final String applicationName = getContext ().getString (R .string .app_name );
7276
73- final MatrixCursor .RowBuilder row = result .newRow ();
74- row .add (Root .COLUMN_ROOT_ID , getDocIdForFile (BASE_DIR ));
75- row .add (Root .COLUMN_DOCUMENT_ID , getDocIdForFile (BASE_DIR ));
76- row .add (Root .COLUMN_SUMMARY , null );
77- row .add (Root .COLUMN_FLAGS , Root .FLAG_SUPPORTS_CREATE | Root .FLAG_SUPPORTS_SEARCH | Root .FLAG_SUPPORTS_IS_CHILD );
78- row .add (Root .COLUMN_TITLE , applicationName );
79- row .add (Root .COLUMN_MIME_TYPES , ALL_MIME_TYPES );
80- row .add (Root .COLUMN_AVAILABLE_BYTES , BASE_DIR .getFreeSpace ());
81- row .add (Root .COLUMN_ICON , R .mipmap .ic_launcher );
77+ if (BuildConfig .PLAY_STORE_BUILD ) {
78+ final File CORE_DIR = new File (getContext ().getFilesDir ().getParent ());
79+ final MatrixCursor .RowBuilder core = result .newRow ();
80+ core .add (Root .COLUMN_ROOT_ID , getDocIdForFile (CORE_DIR ));
81+ core .add (Root .COLUMN_DOCUMENT_ID , getDocIdForFile (CORE_DIR ));
82+ core .add (Root .COLUMN_SUMMARY , "Core Data" );
83+ core .add (Root .COLUMN_FLAGS , Root .FLAG_SUPPORTS_CREATE | Root .FLAG_SUPPORTS_SEARCH | Root .FLAG_SUPPORTS_IS_CHILD );
84+ core .add (Root .COLUMN_TITLE , applicationName );
85+ core .add (Root .COLUMN_MIME_TYPES , ALL_MIME_TYPES );
86+ core .add (Root .COLUMN_AVAILABLE_BYTES , CORE_DIR .getFreeSpace ());
87+ core .add (Root .COLUMN_ICON , R .mipmap .ic_launcher );
88+
89+ final File USER_DIR = new File (Environment .getExternalStorageDirectory ().getAbsolutePath () + "/Android/data/" + getContext ().getPackageName () + "/files/RetroArch" );
90+ final MatrixCursor .RowBuilder user = result .newRow ();
91+ user .add (Root .COLUMN_ROOT_ID , getDocIdForFile (USER_DIR ));
92+ user .add (Root .COLUMN_DOCUMENT_ID , getDocIdForFile (USER_DIR ));
93+ user .add (Root .COLUMN_SUMMARY , "User Data" );
94+ user .add (Root .COLUMN_FLAGS , Root .FLAG_SUPPORTS_CREATE | Root .FLAG_SUPPORTS_SEARCH | Root .FLAG_SUPPORTS_IS_CHILD );
95+ user .add (Root .COLUMN_TITLE , applicationName );
96+ user .add (Root .COLUMN_MIME_TYPES , ALL_MIME_TYPES );
97+ user .add (Root .COLUMN_AVAILABLE_BYTES , USER_DIR .getFreeSpace ());
98+ user .add (Root .COLUMN_ICON , R .mipmap .ic_launcher );
99+ } else {
100+ final File BASE_DIR = new File (getContext ().getFilesDir ().getParent ());
101+ final MatrixCursor .RowBuilder row = result .newRow ();
102+ row .add (Root .COLUMN_ROOT_ID , getDocIdForFile (BASE_DIR ));
103+ row .add (Root .COLUMN_DOCUMENT_ID , getDocIdForFile (BASE_DIR ));
104+ row .add (Root .COLUMN_SUMMARY , null );
105+ row .add (Root .COLUMN_FLAGS , Root .FLAG_SUPPORTS_CREATE | Root .FLAG_SUPPORTS_SEARCH | Root .FLAG_SUPPORTS_IS_CHILD );
106+ row .add (Root .COLUMN_TITLE , applicationName );
107+ row .add (Root .COLUMN_MIME_TYPES , ALL_MIME_TYPES );
108+ row .add (Root .COLUMN_AVAILABLE_BYTES , BASE_DIR .getFreeSpace ());
109+ row .add (Root .COLUMN_ICON , R .mipmap .ic_launcher );
110+ }
111+
82112 return result ;
83113 }
84114
@@ -89,13 +119,44 @@ public Cursor queryDocument(String documentId, String[] projection) throws FileN
89119 return result ;
90120 }
91121
122+ @ Override
123+ public String moveDocument (String sourceDocumentId , String sourceParentDocumentId , String targetParentDocumentId ) throws FileNotFoundException {
124+ File sourceFile = getFileForDocId (sourceDocumentId );
125+ File targetParentFile = getFileForDocId (targetParentDocumentId );
126+ File destination = new File (targetParentFile , sourceFile .getName ());
127+
128+ boolean success = sourceFile .renameTo (destination );
129+ if (!success ){
130+ throw new FileNotFoundException ("Failed to move file " + sourceDocumentId + " to " + targetParentDocumentId );
131+ }
132+
133+ getContext ().getContentResolver ().notifyChange (DocumentsContract .buildTreeDocumentUri (DOCUMENTS_AUTHORITY , sourceParentDocumentId ), null );
134+ getContext ().getContentResolver ().notifyChange (DocumentsContract .buildTreeDocumentUri (DOCUMENTS_AUTHORITY , targetParentDocumentId ), null );
135+ return getDocIdForFile (destination );
136+ }
137+
138+ @ Override
139+ public String renameDocument (String documentId , String displayName ) throws FileNotFoundException {
140+ File document = getFileForDocId (documentId );
141+ File destination = new File (document .getParentFile (), displayName );
142+
143+ boolean success = document .renameTo (destination );
144+ if (!success ){
145+ throw new FileNotFoundException ("Failed to rename file " + documentId + " to " + displayName );
146+ }
147+
148+ getContext ().getContentResolver ().notifyChange (DocumentsContract .buildTreeDocumentUri (DOCUMENTS_AUTHORITY , getDocIdForFile (document .getParentFile ())), null );
149+ return getDocIdForFile (destination );
150+ }
151+
92152 @ Override
93153 public Cursor queryChildDocuments (String parentDocumentId , String [] projection , String sortOrder ) throws FileNotFoundException {
94154 final MatrixCursor result = new MatrixCursor (projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION );
95155 final File parent = getFileForDocId (parentDocumentId );
96156 for (File file : parent .listFiles ()) {
97157 includeFile (result , null , file );
98158 }
159+ result .setNotificationUri (getContext ().getContentResolver (), DocumentsContract .buildTreeDocumentUri (DOCUMENTS_AUTHORITY , parentDocumentId ));
99160 return result ;
100161 }
101162
@@ -115,6 +176,7 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHi
115176
116177 @ Override
117178 public boolean onCreate () {
179+ DOCUMENTS_AUTHORITY = getContext ().getPackageName () + ".documents" ;
118180 return true ;
119181 }
120182
@@ -138,14 +200,25 @@ public String createDocument(String parentDocumentId, String mimeType, String di
138200 } catch (IOException e ) {
139201 throw new FileNotFoundException ("Failed to create document with id " + newFile .getPath ());
140202 }
203+ getContext ().getContentResolver ().notifyChange (DocumentsContract .buildTreeDocumentUri (DOCUMENTS_AUTHORITY , parentDocumentId ), null );
141204 return newFile .getPath ();
142205 }
143206
144207 @ Override
145208 public void deleteDocument (String documentId ) throws FileNotFoundException {
146209 File file = getFileForDocId (documentId );
147- if (!file .delete ()) {
148- throw new FileNotFoundException ("Failed to delete document with id " + documentId );
210+ rm_r (file );
211+ getContext ().getContentResolver ().notifyChange (DocumentsContract .buildTreeDocumentUri (DOCUMENTS_AUTHORITY , getDocIdForFile (file .getParentFile ())), null );
212+ }
213+
214+ void rm_r (File file ) throws FileNotFoundException {
215+ if (file .isDirectory ()){
216+ for (File child : file .listFiles ()) {
217+ rm_r (child );
218+ }
219+ }
220+ if (!file .delete ()){
221+ throw new FileNotFoundException ("Could not delete file " + file .getPath ());
149222 }
150223 }
151224
@@ -248,11 +321,11 @@ private void includeFile(MatrixCursor result, String docId, File file)
248321
249322 int flags = 0 ;
250323 if (file .isDirectory ()) {
251- if (file .canWrite ()) flags |= Document .FLAG_DIR_SUPPORTS_CREATE ;
252- } else if ( file . canWrite ()) {
253- flags |= Document .FLAG_SUPPORTS_WRITE ;
324+ if (file .canWrite ()) flags |= Document .FLAG_DIR_SUPPORTS_CREATE | Document . FLAG_SUPPORTS_RENAME ;
325+ } else {
326+ if ( file . canWrite ()) flags |= Document .FLAG_SUPPORTS_WRITE | Document . FLAG_SUPPORTS_RENAME ;
254327 }
255- if (file .getParentFile ().canWrite ()) flags |= Document .FLAG_SUPPORTS_DELETE ;
328+ if (file .getParentFile ().canWrite ()) flags |= Document .FLAG_SUPPORTS_DELETE | Document . FLAG_SUPPORTS_MOVE ;
256329
257330 final String displayName = file .getName ();
258331 final String mimeType = getMimeType (file );
0 commit comments