@@ -6,45 +6,35 @@ import android.database.Cursor
66import android.net.Uri
77import android.provider.DocumentsContract
88import com.lazygeniouz.dfc.file.DocumentFileCompat
9- import com.lazygeniouz.dfc.file.internals.SingleDocumentFileCompat
109import com.lazygeniouz.dfc.file.internals.TreeDocumentFileCompat
11- import com.lazygeniouz.dfc.logger.ErrorLogger.logError
10+ import com.lazygeniouz.dfc.logger.ErrorLogger
1211
1312/* *
14- * This class calls relevant queries on the [ContentResolver]
15- *
16- * @param context Required to access the underlying **ContentResolver**
13+ * Helper class for calling relevant methods on [DocumentsContract] & queries via [ContentResolver].
1714 */
18- internal class ResolverCompat (
19- private val context : Context ,
20- private val uri : Uri ,
21- ) {
15+ internal object ResolverCompat {
2216
23- // Projections
24- private val _idProjection = DocumentsContract .Document .COLUMN_DOCUMENT_ID
25- private val documentIdProjection = arrayOf(_idProjection )
26- private val fullProjection = arrayOf(
27- _idProjection ,
17+ private val iconProjection = arrayOf(DocumentsContract .Document .COLUMN_ICON )
18+ private val idProjection = arrayOf(DocumentsContract .Document .COLUMN_DOCUMENT_ID )
19+ val fullProjection = arrayOf(
20+ DocumentsContract .Document .COLUMN_DOCUMENT_ID ,
2821 DocumentsContract .Document .COLUMN_DISPLAY_NAME ,
2922 DocumentsContract .Document .COLUMN_SIZE ,
3023 DocumentsContract .Document .COLUMN_LAST_MODIFIED ,
3124 DocumentsContract .Document .COLUMN_MIME_TYPE ,
3225 DocumentsContract .Document .COLUMN_FLAGS
3326 )
3427
35- // The star of the show!
36- private val contentResolver by lazy { context.contentResolver }
37-
3828 /* *
3929 * Delete the file.
4030 *
4131 * @return True if deletion succeeded, False otherwise
4232 */
43- internal fun deleteDocument (): Boolean {
33+ internal fun deleteDocument (context : Context , uri : Uri ): Boolean {
4434 return try {
45- DocumentsContract .deleteDocument(contentResolver, uri)
35+ DocumentsContract .deleteDocument(context. contentResolver, uri)
4636 } catch (exception: Exception ) {
47- logError(" Exception while deleting document" , exception)
37+ ErrorLogger . logError(" Exception while deleting document" , exception)
4838 false
4939 }
5040 }
@@ -54,12 +44,12 @@ internal class ResolverCompat(
5444 *
5545 * Returns True if the rename was successful, False otherwise.
5646 */
57- internal fun renameTo (name : String ): Boolean {
47+ internal fun renameTo (context : Context , uri : Uri , name : String ): Uri ? {
5848 return try {
59- ( DocumentsContract .renameDocument(contentResolver, uri, name) != null )
49+ return DocumentsContract .renameDocument(context. contentResolver, uri, name)
6050 } catch (exception: Exception ) {
61- logError(" Exception while renaming document" , exception)
62- false
51+ ErrorLogger . logError(" Exception while renaming document" , exception)
52+ null
6353 }
6454 }
6555
@@ -71,22 +61,15 @@ internal class ResolverCompat(
7161 *
7262 * @return A Uri if file was created successfully, **null** if any exception was caught.
7363 */
74- internal fun createFile (mimeType : String , name : String ): Uri ? {
64+ internal fun createFile (context : Context , uri : Uri , mimeType : String , name : String ): Uri ? {
7565 return try {
76- DocumentsContract .createDocument(contentResolver, uri, mimeType, name)
66+ DocumentsContract .createDocument(context. contentResolver, uri, mimeType, name)
7767 } catch (exception: Exception ) {
78- logError(" Exception while creating a document" , exception)
68+ ErrorLogger . logError(" Exception while creating a document" , exception)
7969 null
8070 }
8171 }
8272
83- /* *
84- * Queries the ContentResolver & builds a list of [DocumentFileCompat] with all the required fields.
85- */
86- internal fun queryAndMakeDocumentList (): List <DocumentFileCompat > {
87- return runTreeQuery()
88- }
89-
9073 /* *
9174 * Returns the children count without creating [DocumentFileCompat] objects.
9275 *
@@ -96,109 +79,63 @@ internal class ResolverCompat(
9679 * - Min: 0.275, Max: 0.613 (listFiles().size)
9780 * - Avg: 0.444, Diff: 0.338, % Change: 55.14
9881 */
99- internal fun count (): Int {
100- val childrenUri = buildChildDocumentsUriUsingTree()
101- val projection = arrayOf(DocumentsContract .Document .COLUMN_ICON )
102- getCursor(childrenUri, projection)?.use { cursor -> return cursor.count }
82+ internal fun count (context : Context , uri : Uri ): Int {
83+ val childrenUri = createChildrenUri(uri)
84+ getCursor(context, childrenUri, iconProjection)?.use { cursor -> return cursor.count }
10385 return 0
10486 }
10587
106- // Returns True if the Uri is a Tree Uri, False otherwise.
107- private fun isTreeUri (): Boolean {
108- val paths = uri.pathSegments
109- return paths.size >= 2 && " tree" == paths[0 ]
110- }
111-
112- // Create a child document uri from the tree uri.
113- private fun buildChildDocumentsUriUsingTree (): Uri {
114- return DocumentsContract .buildChildDocumentsUriUsingTree(
115- getTreeUri(), DocumentsContract .getDocumentId(getTreeUri())
116- )
117- }
118-
119- // Build relevant Tree Uri.
120- private fun getTreeUri (): Uri {
121- val isDocument = DocumentsContract .isDocumentUri(context, uri)
122- return DocumentsContract .buildDocumentUriUsingTree(
123- uri, if (isDocument) DocumentsContract .getDocumentId(uri)
124- else DocumentsContract .getTreeDocumentId(uri)
125- )
126- }
127-
128- /* *
129- * Builds a complete [DocumentFileCompat] object
130- * when a first call to building a [TreeDocumentFileCompat] or a [SingleDocumentFileCompat] is made.
131- *
132- * @param isTree Returns a [TreeDocumentFileCompat] if True, [SingleDocumentFileCompat] otherwise.
133- *
134- * @throws UnsupportedOperationException If `isTree` is True but the Uri is not Tree based.
135- */
136- internal fun getInitialFileCompat (isTree : Boolean ): DocumentFileCompat ? {
137- if (isTree && ! isTreeUri())
138- throw UnsupportedOperationException (" Document Uri is not a Tree uri." )
139- return runInitialQuery(isTree)
140- }
141-
14288 /* *
14389 * Returns True if the Document Folder / File exists, False otherwise.
14490 */
145- internal fun exists (): Boolean {
146- getCursor(uri, documentIdProjection )?.use { cursor -> return (cursor.count > 0 ) }
91+ internal fun exists (context : Context , uri : Uri ): Boolean {
92+ getCursor(context, uri, idProjection )?.use { cursor -> return (cursor.count > 0 ) }
14793 return false
14894 }
14995
150- // Get a Cursor to query the given Uri against provided projection
151- private fun getCursor (uri : Uri , projection : Array <String >): Cursor ? {
152- return contentResolver.query(uri, projection, null , null , null )
153- }
154-
15596 /* *
156- * Runs query to build initial [TreeDocumentFileCompat] or a [SingleDocumentFileCompat].
157- *
158- * @param isTree Returns a [TreeDocumentFileCompat] if True, [SingleDocumentFileCompat] otherwise.
97+ * Queries the ContentResolver & builds a list of [DocumentFileCompat] with all the required fields.
15998 */
160- private fun runInitialQuery (isTree : Boolean ): DocumentFileCompat ? {
161- val uriToQuery = if (! isTree) uri
162- else DocumentsContract .buildDocumentUriUsingTree(
163- getTreeUri(), DocumentsContract .getDocumentId(getTreeUri())
164- )
165-
166- var document: DocumentFileCompat ? = null
99+ internal fun listFiles (context : Context , uri : Uri ): List <DocumentFileCompat > {
100+ val childrenUri = createChildrenUri(uri)
101+ // empty list
102+ val listOfDocuments = arrayListOf<DocumentFileCompat >()
167103
168- getCursor(uriToQuery , fullProjection)?.use { cursor ->
169- if (cursor.moveToFirst ()) {
104+ getCursor(context, childrenUri , fullProjection)?.use { cursor ->
105+ while (cursor.moveToNext ()) {
170106 val documentId: String = cursor.getString(0 )
171- val documentUri: Uri = if (! isTree) uri
172- else DocumentsContract .buildDocumentUriUsingTree(getTreeUri(), documentId)
173-
174- // Same logic but moved to separate classes for easy readability & understanding.
175- document = if (! isTree) SingleDocumentFileCompat .make(context, cursor, documentUri)
176- else TreeDocumentFileCompat .make(context, cursor, documentUri)
107+ val documentUri = DocumentsContract .buildDocumentUriUsingTree(uri, documentId)
108+
109+ val documentName: String = cursor.getString(1 )
110+ val documentSize: Long = cursor.getLong(2 )
111+ val documentLastModified: Long = cursor.getLong(3 )
112+ val documentMimeType: String = cursor.getString(4 )
113+ val documentFlags: Int = cursor.getLong(5 ).toInt()
114+
115+ TreeDocumentFileCompat (
116+ context, documentUri, documentName,
117+ documentSize, documentLastModified,
118+ documentMimeType, documentFlags
119+ ).also { childFile -> listOfDocuments.add(childFile) }
177120 }
178121 }
179122
180- return document
123+ return listOfDocuments
181124 }
182125
183126 /* *
184- * Run query on the passed uri with full projections.
185- *
186- * @return A list of [DocumentFileCompat] with all fields.
127+ * Get [Cursor] from [ContentResolver.query] with given [projection] on a given [uri].
187128 */
188- private fun runTreeQuery (): List <DocumentFileCompat > {
189- val childrenUri = buildChildDocumentsUriUsingTree()
190-
191- // empty list
192- val listOfDocuments = arrayListOf<DocumentFileCompat >()
193-
194- getCursor(childrenUri, fullProjection)?.use { cursor ->
195- while (cursor.moveToNext()) {
196- val docId: String = cursor.getString(0 )
197- val docUri = DocumentsContract .buildDocumentUriUsingTree(getTreeUri(), docId)
198- listOfDocuments.add(TreeDocumentFileCompat .make(context, cursor, docUri))
199- }
200- }
129+ fun getCursor (context : Context , uri : Uri , projection : Array <String >): Cursor ? {
130+ return context.contentResolver.query(
131+ uri, projection, null , null , null
132+ )
133+ }
201134
202- return listOfDocuments
135+ // Make children uri for query.
136+ private fun createChildrenUri (uri : Uri ): Uri {
137+ return DocumentsContract .buildChildDocumentsUriUsingTree(
138+ uri, DocumentsContract .getDocumentId(uri)
139+ )
203140 }
204141}
0 commit comments