Skip to content

Commit 0ac0457

Browse files
committed
Rewrite document creation, listing and other required logic.
1 parent 631da73 commit 0ac0457

3 files changed

Lines changed: 92 additions & 47 deletions

File tree

dfc/src/main/java/com/lazygeniouz/dfc/file/DocumentFileCompat.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import android.provider.DocumentsContract.Document.MIME_TYPE_DIR
88
import android.provider.DocumentsContract.isDocumentUri
99
import com.lazygeniouz.dfc.controller.DocumentController
1010
import com.lazygeniouz.dfc.file.internals.RawDocumentFileCompat
11-
import com.lazygeniouz.dfc.resolver.ResolverCompat
11+
import com.lazygeniouz.dfc.file.internals.SingleDocumentFileCompat
12+
import com.lazygeniouz.dfc.file.internals.TreeDocumentFileCompat
1213
import java.io.File
1314

1415
/**
@@ -198,7 +199,7 @@ abstract class DocumentFileCompat constructor(
198199
*/
199200
@JvmStatic
200201
fun fromTreeUri(context: Context, uri: Uri): DocumentFileCompat? {
201-
return ResolverCompat(context, uri).getInitialFileCompat(true)
202+
return TreeDocumentFileCompat.make(context, uri, true)
202203
}
203204

204205
/**
@@ -209,7 +210,7 @@ abstract class DocumentFileCompat constructor(
209210
*/
210211
@JvmStatic
211212
fun fromSingleUri(context: Context, uri: Uri): DocumentFileCompat? {
212-
return ResolverCompat(context, uri).getInitialFileCompat(false)
213+
return SingleDocumentFileCompat.make(context, uri)
213214
}
214215

215216
/**

dfc/src/main/java/com/lazygeniouz/dfc/file/internals/SingleDocumentFileCompat.kt

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.lazygeniouz.dfc.file.internals
22

33
import android.content.Context
4-
import android.database.Cursor
54
import android.net.Uri
65
import com.lazygeniouz.dfc.file.DocumentFileCompat
6+
import com.lazygeniouz.dfc.resolver.ResolverCompat
77

88
/**
99
* SingleFileCompat serves as an alternative to the **SingleDocumentFile**
@@ -15,7 +15,7 @@ import com.lazygeniouz.dfc.file.DocumentFileCompat
1515
* Other params same as [DocumentFileCompat].
1616
*/
1717
internal class SingleDocumentFileCompat(
18-
context: Context, documentUri: String, documentName: String = "", documentSize: Long = 0,
18+
context: Context, documentUri: Uri, documentName: String = "", documentSize: Long = 0,
1919
lastModifiedTime: Long = -1L, documentMimeType: String = "", documentFlags: Int = -1,
2020
) : DocumentFileCompat(
2121
context, documentUri, documentName, documentSize,
@@ -41,7 +41,7 @@ internal class SingleDocumentFileCompat(
4141
}
4242

4343
/**
44-
* Cannot iterate a File.
44+
* Cannot iterate a single document.
4545
*
4646
* @throws UnsupportedOperationException
4747
*/
@@ -50,10 +50,12 @@ internal class SingleDocumentFileCompat(
5050
}
5151

5252
/**
53-
* Not a Directory, no children, no count.
53+
* No [listFiles], no children, no count.
54+
*
55+
* @throws UnsupportedOperationException
5456
*/
5557
override fun count(): Int {
56-
return 0
58+
throw UnsupportedOperationException()
5759
}
5860

5961
/**
@@ -65,6 +67,15 @@ internal class SingleDocumentFileCompat(
6567
throw UnsupportedOperationException()
6668
}
6769

70+
/**
71+
* [SingleDocumentFileCompat] has limited access and permissions to the [uri].
72+
*
73+
* @throws UnsupportedOperationException
74+
*/
75+
override fun renameTo(name: String): Boolean {
76+
throw UnsupportedOperationException()
77+
}
78+
6879
// Copies current file to the destination uri.
6980
override fun copyTo(destination: Uri) {
7081
val inputStream = context.contentResolver.openInputStream(uri)!!
@@ -82,25 +93,27 @@ internal class SingleDocumentFileCompat(
8293
internal companion object {
8394

8495
/**
85-
* Extracted in to a separate companion method to not clutter common code while running the
86-
* **ContentResolver Queries**.
96+
* Build a [SingleDocumentFileCompat] from a given [uri].
8797
*/
88-
internal fun make(
89-
context: Context,
90-
cursor: Cursor, documentUri: Uri,
91-
): SingleDocumentFileCompat {
92-
// cursor.getString(0) is the documentId
93-
val documentName: String = cursor.getString(1)
94-
val documentSize: Long = cursor.getLong(2)
95-
val documentLastModified: Long = cursor.getLong(3)
96-
val documentMimeType: String = cursor.getString(4)
97-
val documentFlags: Int = cursor.getLong(5).toInt()
98+
internal fun make(context: Context, self: Uri): SingleDocumentFileCompat? {
99+
ResolverCompat.getCursor(context, self, ResolverCompat.fullProjection)
100+
?.use { cursor ->
101+
if (cursor.moveToFirst()) {
102+
val documentName: String = cursor.getString(1)
103+
val documentSize: Long = cursor.getLong(2)
104+
val documentLastModified: Long = cursor.getLong(3)
105+
val documentMimeType: String = cursor.getString(4)
106+
val documentFlags: Int = cursor.getLong(5).toInt()
107+
108+
return SingleDocumentFileCompat(
109+
context, self,
110+
documentName, documentSize,
111+
documentLastModified, documentMimeType, documentFlags
112+
)
113+
}
114+
}
98115

99-
return SingleDocumentFileCompat(
100-
context, documentUri.toString(),
101-
documentName, documentSize,
102-
documentLastModified, documentMimeType, documentFlags
103-
)
116+
return null
104117
}
105118
}
106119
}

dfc/src/main/java/com/lazygeniouz/dfc/file/internals/TreeDocumentFileCompat.kt

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package com.lazygeniouz.dfc.file.internals
22

33
import android.content.Context
4-
import android.database.Cursor
54
import android.net.Uri
5+
import android.provider.DocumentsContract
66
import android.provider.DocumentsContract.Document.MIME_TYPE_DIR
77
import com.lazygeniouz.dfc.file.DocumentFileCompat
8+
import com.lazygeniouz.dfc.resolver.ResolverCompat
89

910
/**
1011
* TreeFileCompat serves as an alternative to the **TreeDocumentFile**
@@ -17,7 +18,7 @@ import com.lazygeniouz.dfc.file.DocumentFileCompat
1718
* Other params same as [DocumentFileCompat].
1819
*/
1920
internal class TreeDocumentFileCompat constructor(
20-
context: Context, documentUri: String, documentName: String = "", documentSize: Long = 0,
21+
context: Context, documentUri: Uri, documentName: String = "", documentSize: Long = 0,
2122
lastModifiedTime: Long = -1L, documentMimeType: String = "", documentFlags: Int = -1,
2223
) : DocumentFileCompat(
2324
context, documentUri, documentName, documentSize,
@@ -34,7 +35,7 @@ internal class TreeDocumentFileCompat constructor(
3435
*/
3536
override fun createFile(mimeType: String, name: String): DocumentFileCompat? {
3637
val treeFileUri = fileController.createFile(mimeType, name)
37-
return treeFileUri?.let { fromTreeUri(context, treeFileUri) }
38+
return treeFileUri?.let { make(context, treeFileUri, false) }
3839
}
3940

4041
/**
@@ -46,7 +47,7 @@ internal class TreeDocumentFileCompat constructor(
4647
*/
4748
override fun createDirectory(name: String): DocumentFileCompat? {
4849
val treeFileUri = fileController.createFile(MIME_TYPE_DIR, name)
49-
return treeFileUri?.let { fromTreeUri(context, treeFileUri) }
50+
return treeFileUri?.let { make(context, treeFileUri, false) }
5051
}
5152

5253
/**
@@ -73,6 +74,17 @@ internal class TreeDocumentFileCompat constructor(
7374
return listFiles().firstOrNull { file -> file.name.isNotEmpty() && file.name == name }
7475
}
7576

77+
/**
78+
* A [TreeDocumentFileCompat] has a wider range of permissions & hence supports rename.
79+
*
80+
* @return True if the rename was successful, False otherwise.
81+
*/
82+
override fun renameTo(name: String): Boolean {
83+
val newUri = fileController.renameTo(name)
84+
if (newUri != null) uri = newUri
85+
return newUri != null
86+
}
87+
7688
/**
7789
* Copy would work only if the underlying Uri is a SingleDocumentFile or a File.
7890
*/
@@ -90,25 +102,44 @@ internal class TreeDocumentFileCompat constructor(
90102
internal companion object {
91103

92104
/**
93-
* Extracted in to a separate companion method to not clutter common code while running the
94-
* **ContentResolver Queries**.
105+
* Return whether the given [uri] is a tree uri.
95106
*/
96-
internal fun make(
97-
context: Context,
98-
cursor: Cursor, documentUri: Uri,
99-
): TreeDocumentFileCompat {
100-
// cursor.getString(0) is the documentId
101-
val documentName: String = cursor.getString(1)
102-
val documentSize: Long = cursor.getLong(2)
103-
val documentLastModified: Long = cursor.getLong(3)
104-
val documentMimeType: String = cursor.getString(4)
105-
val documentFlags: Int = cursor.getLong(5).toInt()
106-
107-
return TreeDocumentFileCompat(
108-
context, documentUri.toString(),
109-
documentName, documentSize,
110-
documentLastModified, documentMimeType, documentFlags
111-
)
107+
private fun isTreeUri(uri: Uri): Boolean {
108+
val paths = uri.pathSegments
109+
return paths.size >= 2 && "tree" == paths[0]
110+
}
111+
112+
/**
113+
* Build the initial [TreeDocumentFileCompat] from a given [uri].
114+
*/
115+
internal fun make(context: Context, uri: Uri, isInitial: Boolean): TreeDocumentFileCompat? {
116+
if (!isTreeUri(uri)) {
117+
throw UnsupportedOperationException("Document Uri is not a Tree uri.")
118+
}
119+
120+
// build a new tree uri if this is a first tree doc creation...
121+
val treeUri = if (isInitial) DocumentsContract.buildDocumentUriUsingTree(
122+
uri, DocumentsContract.getTreeDocumentId(uri)
123+
) else uri
124+
125+
ResolverCompat.getCursor(context, treeUri, ResolverCompat.fullProjection)
126+
?.use { cursor ->
127+
if (cursor.moveToFirst()) {
128+
val documentName: String = cursor.getString(1)
129+
val documentSize: Long = cursor.getLong(2)
130+
val documentLastModified: Long = cursor.getLong(3)
131+
val documentMimeType: String = cursor.getString(4)
132+
val documentFlags: Int = cursor.getLong(5).toInt()
133+
134+
return TreeDocumentFileCompat(
135+
context, treeUri,
136+
documentName, documentSize,
137+
documentLastModified, documentMimeType, documentFlags
138+
)
139+
}
140+
}
141+
142+
return null
112143
}
113144
}
114145
}

0 commit comments

Comments
 (0)