Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6e046f0
Enable listing the contents of a SAF subfolder
Jun 13, 2022
982cbae
Document ability to list subdirectories.
Jun 13, 2022
85f9f74
docs: update README.md [skip ci]
allcontributors[bot] Jun 13, 2022
8e16ea7
docs: update docs/index.md [skip ci]
allcontributors[bot] Jun 13, 2022
2918fdd
docs: update .all-contributorsrc [skip ci]
allcontributors[bot] Jun 13, 2022
adc9e16
Merge pull request #60 from lakscastro/all-contributors/add-EternityF…
Jun 13, 2022
b8a58a5
(#59) Tiny comment improvements
Jun 14, 2022
9eba51d
Merge pull request #59 from EternityForest/fix-subdir-list
Jun 14, 2022
2b9a855
(#62) Apply fix and remove Android specific APIs
Jun 30, 2022
26a70e8
(#62) Remove unused imports
Jun 30, 2022
4e5f031
(#62) Remove unused code and expressions
Jun 30, 2022
6f8c61f
(#62) Remove unnecessary `rootUri` param
Jul 1, 2022
e253de6
(#62) Rename `/example` widget components
Jul 1, 2022
bf06b63
(#62) Remove unused SDK constraint
Jul 1, 2022
f950397
(#62) Improve `/example` comment
Jul 1, 2022
93d3d61
(#62) Add `v0.4.0` changes to `CHANGELOG.md`
Jul 1, 2022
6b61eae
(#62) Add last change and contributor reference
Jul 1, 2022
05b9d9f
Merge pull request #63 from lakscastro/feat/list-subfolder-contents
Jul 1, 2022
3a62feb
Merge pull request #65 from lakscastro/docs/v0.4.0-changelog
Jul 1, 2022
1515cdd
(#65) Set package version to `v0.4.0`
Jul 1, 2022
ebe3e07
(#65) Improve `README.md`
Jul 1, 2022
108f900
Merge pull request #66 from lakscastro/chore/set-package-version-to-v…
Jul 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@
"avatar_url": "https://avatars.githubusercontent.com/u/758047?v=4",
"profile": "https://eternityforest.com",
"contributions": [
"bug"
"bug",
"code",
"doc"
]
}
],
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## 0.4.0

Fix the current behavior of `listFiles` and `openDocumentFile` API.

### Improvements

- It's now possible to list contents of all subfolders of a granted Uri opened from `openDocumentTree` ([@EternityForest](https://github.com/EternityForest)).
- Now `ACTION_VIEW` intent builder through `openDocumentFile` API was fixed. So it's now possible to open any file of any kind in third party apps without needing specify the mime type.

### Breaking changes

- Removed Android specific APIs:
- `DocumentFile.listFiles` (Now it's only available globally).
- `buildDocumentUriUsingTree` removed due high coupling with Android API (Android specific API that are not useful on any other platforms).
- `buildDocumentUri` removed due high coupling with Android API (Android specific API that are not useful on any other platforms).
- `buildTreeDocumentUri` removed due high coupling with Android API (Android specific API that are not useful on any other platforms).
- `getDocumentThumbnail` now receives only the `uri` param instead of a `rootUri` and a `documentId`.
- `rootUri` field from `QueryMetadata` was removed due API ambiguity: there's no such concept in the Android API and this is not required by it to work well.

## 0.3.1

Minor improvements and bug fixes:
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@

## Documentation

#### See the website for [documentation](https://lakscastro.github.io/shared-storage)
See the website for [documentation](https://lakscastro.github.io/shared-storage).

All documentation is also available under `/docs` to each released version which is the data source of the website.

You can contribute to the documentation by just editing these files through the GitHub web editor!

To check all ways you can contribute to this package see [Contributing/Ways to contribute](https://lakscastro.github.io/shared-storage/Contributing/Ways%20to%20contribute/).

Latest changes are available on `master` branch and the actual latest published package version lives under `release` branch.

All other branches are derivated from issues, new features or bug fixes.
Expand All @@ -46,7 +48,7 @@ These are the brilliant minds behind the development of this plugin!
<td align="center"><a href="https://www.bibliotecaortodoxa.ro"><img src="https://avatars.githubusercontent.com/u/1148228?v=4?s=100" width="100px;" alt=""/><br /><sub><b>www.bibliotecaortodoxa.ro</b></sub></a><br /><a href="https://github.com/lakscastro/shared-storage/commits?author=aplicatii-romanesti" title="Code">💻</a> <a href="https://github.com/lakscastro/shared-storage/issues?q=author%3Aaplicatii-romanesti" title="Bug reports">🐛</a> <a href="#ideas-aplicatii-romanesti" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/dangilbert"><img src="https://avatars.githubusercontent.com/u/6799566?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dangilbert</b></sub></a><br /><a href="https://github.com/lakscastro/shared-storage/commits?author=dangilbert" title="Code">💻</a> <a href="https://github.com/lakscastro/shared-storage/issues?q=author%3Adangilbert" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/dhaval-k-simformsolutions"><img src="https://avatars.githubusercontent.com/u/90894202?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dhaval-k-simformsolutions</b></sub></a><br /><a href="https://github.com/lakscastro/shared-storage/issues?q=author%3Adhaval-k-simformsolutions" title="Bug reports">🐛</a> <a href="#ideas-dhaval-k-simformsolutions" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://eternityforest.com"><img src="https://avatars.githubusercontent.com/u/758047?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Dunn</b></sub></a><br /><a href="https://github.com/lakscastro/shared-storage/issues?q=author%3AEternityForest" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://eternityforest.com"><img src="https://avatars.githubusercontent.com/u/758047?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Dunn</b></sub></a><br /><a href="https://github.com/lakscastro/shared-storage/issues?q=author%3AEternityForest" title="Bug reports">🐛</a> <a href="https://github.com/lakscastro/shared-storage/commits?author=EternityForest" title="Code">💻</a> <a href="https://github.com/lakscastro/shared-storage/commits?author=EternityForest" title="Documentation">📖</a></td>
</tr>
</table>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import io.lakscastro.sharedstorage.ROOT_CHANNEL
import io.lakscastro.sharedstorage.SharedStoragePlugin
import io.lakscastro.sharedstorage.plugin.*
import io.lakscastro.sharedstorage.storageaccessframework.lib.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
* Aimed to implement strictly only the APIs already available from the native and original
Expand Down Expand Up @@ -75,57 +75,73 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :
)
}
PERSISTED_URI_PERMISSIONS ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
persistedUriPermissions(result)
}
persistedUriPermissions(result)
RELEASE_PERSISTABLE_URI_PERMISSION ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
releasePersistableUriPermission(result, call.argument<String?>("uri") as String)
}
releasePersistableUriPermission(
result,
call.argument<String?>("uri") as String
)
FROM_TREE_URI ->
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
createDocumentFileMap(
documentFromUri(plugin.context, call.argument<String?>("uri") as String)
)
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
createDocumentFileMap(
documentFromUri(
plugin.context,
call.argument<String?>("uri") as String
)
)
}
)
}
CAN_WRITE ->
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
documentFromUri(plugin.context, call.argument<String?>("uri") as String)?.canWrite()
)
}
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
documentFromUri(
plugin.context,
call.argument<String?>("uri") as String
)?.canWrite()
)
}
CAN_READ ->
if (Build.VERSION.SDK_INT >= API_21) {
val uri = call.argument<String?>("uri") as String
if (Build.VERSION.SDK_INT >= API_21) {
val uri = call.argument<String?>("uri") as String

result.success(documentFromUri(plugin.context, uri)?.canRead())
}
result.success(documentFromUri(plugin.context, uri)?.canRead())
}
LENGTH ->
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
documentFromUri(plugin.context, call.argument<String?>("uri") as String)?.length()
documentFromUri(
plugin.context,
call.argument<String?>("uri") as String
)?.length()
)
}
EXISTS ->
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
documentFromUri(plugin.context, call.argument<String?>("uri") as String)?.exists()
documentFromUri(
plugin.context,
call.argument<String?>("uri") as String
)?.exists()
)
}
DELETE ->
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
documentFromUri(plugin.context, call.argument<String?>("uri") as String)?.delete()
documentFromUri(
plugin.context,
call.argument<String?>("uri") as String
)?.delete()
)
}
LAST_MODIFIED ->
if (Build.VERSION.SDK_INT >= API_21) {
result.success(
documentFromUri(plugin.context, call.argument<String?>("uri") as String)
?.lastModified()
val document = documentFromUri(
plugin.context,
call.argument<String?>("uri") as String
)

result.success(document?.lastModified())
}
CREATE_DIRECTORY -> {
if (Build.VERSION.SDK_INT >= API_21) {
Expand All @@ -146,7 +162,12 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :
val displayName = call.argument<String?>("displayName") as String

result.success(
createDocumentFileMap(documentFromUri(plugin.context, uri)?.findFile(displayName))
createDocumentFileMap(
documentFromUri(
plugin.context,
uri
)?.findFile(displayName)
)
)
}
}
Expand All @@ -165,9 +186,9 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :
}
} else {
result.notSupported(
RENAME_TO,
API_21,
mapOf("uri" to "$uri", "destination" to "$destination")
RENAME_TO,
API_21,
mapOf("uri" to "$uri", "destination" to "$destination")
)
}
}
Expand All @@ -180,8 +201,13 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :
val success = renameTo(displayName)

result.success(
if (success) createDocumentFileMap(documentFromUri(plugin.context, this.uri)!!)
else null
if (success) createDocumentFileMap(
documentFromUri(
plugin.context,
this.uri
)!!
)
else null
)
}
} else {
Expand Down Expand Up @@ -235,9 +261,9 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :

if (Build.VERSION.SDK_INT >= API_26) {
putExtra(
if (Build.VERSION.SDK_INT >= API_26) DocumentsContract.EXTRA_INITIAL_URI
else DOCUMENTS_CONTRACT_EXTRA_INITIAL_URI,
tree?.uri
if (Build.VERSION.SDK_INT >= API_26) DocumentsContract.EXTRA_INITIAL_URI
else DOCUMENTS_CONTRACT_EXTRA_INITIAL_URI,
tree?.uri
)
}
}
Expand Down Expand Up @@ -380,7 +406,9 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :
eventSink = events

when (args["event"]) {
LIST_FILES -> listFilesEvent(eventSink, args)
LIST_FILES -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
listFilesEvent(eventSink, args)
}
}
}

Expand All @@ -393,42 +421,41 @@ internal class DocumentFileApi(private val plugin: SharedStoragePlugin) :
private fun listFilesEvent(eventSink: EventChannel.EventSink?, args: Map<*, *>) {
if (eventSink == null) return

val document =
if (Build.VERSION.SDK_INT >= API_24) {
documentFromUri(plugin.context, args["uri"] as String) ?: return
} else {
null
}
val columns = args["columns"] as List<*>
val uri = Uri.parse(args["uri"] as String)
val document = DocumentFile.fromTreeUri(plugin.context, uri)

if (document == null) {
eventSink.error(
EXCEPTION_NOT_SUPPORTED,
"Android SDK must be greater or equal than [Build.VERSION_CODES.N]",
"Got (Build.VERSION.SDK_INT): ${Build.VERSION.SDK_INT}"
EXCEPTION_NOT_SUPPORTED,
"Android SDK must be greater or equal than [Build.VERSION_CODES.N]",
"Got (Build.VERSION.SDK_INT): ${Build.VERSION.SDK_INT}"
)
} else {
val columns = args["columns"] as List<*>

if (!document.canRead()) {
val error = "You cannot read a URI that you don't have read permissions"

Log.d("NO PERMISSION!!!", error)

eventSink.error(EXCEPTION_MISSING_PERMISSIONS, error, mapOf("uri" to args["uri"]))
eventSink.error(
EXCEPTION_MISSING_PERMISSIONS,
error,
mapOf("uri" to args["uri"])
)

eventSink.endOfStream()
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CoroutineScope(Dispatchers.IO).launch {
try {
traverseDirectoryEntries(
plugin.context.contentResolver,
rootOnly = true,
rootUri = document.uri,
columns =
columns
.map { parseDocumentFileColumn(parseDocumentFileColumn(it as String)!!) }
.toTypedArray()
plugin.context.contentResolver,
rootOnly = true,
targetUri = document.uri,
columns =
columns
.map { parseDocumentFileColumn(parseDocumentFileColumn(it as String)!!) }
.toTypedArray()
) { data, _ -> launch(Dispatchers.Main) { eventSink.success(data) } }
} finally {
launch(Dispatchers.Main) { eventSink.endOfStream() }
Expand Down
Loading