Giter VIP home page Giter VIP logo

Comments (9)

anggrayudi avatar anggrayudi commented on September 25, 2024 3

To request the access, you need to call requestStorageAccess(). On Android 11+, you might need to save the granted path to the preferences, because API 30 can't grant the root path, so you'll need remember which path that you have.

storageHelper.onStorageAccessGranted = { _, root ->
    val preferences = PreferenceManager.getDefaultSharedPreferences(this)
    preferences.edit().putString("path", root.getAbsolutePath(this)).apply()
}

To reuse this granted path in the future, call DocumentFileCompat.fromFullPath():

val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val path = preferences.getString("path", null)
val folder = DocumentFileCompat.fromFullPath(this, path!!, requiresWriteAccess = true)
// now you can make file on this folder
val file = folder?.makeFile(this, "notes", "text/plain")

I'm planning to release SimpleStorage v1.5.4 to help you querying all granted paths in your app, so you don't need to remember them in preferences anymore. Here's the sample code will look like:

val grantedPaths: Map<String, Set<String>> = DocumentFileCompat.getAccessibleAbsolutePaths(context)

Here's the output of that new function:

Screenshot 2023-01-05 at 06 01 10

If you can't wait for the release, just use snapshot version 1.5.4-SNAPSHOT in your dependencies.

from simplestorage.

anggrayudi avatar anggrayudi commented on September 25, 2024 3

If you don't use SimpleStorageHelper, then you need to call requestStorageAccess() in FolderPickerCallback#onStorageAccessDenied() callback. But if you're using it, then you can ignore requestStorageAccess(), because SimpleStorageHelper#openFolderPicker() already handles that capability.

From the code you've shared, you're using SimpleStorageHelper, which is recommended for most cases. Then it's ok to ignore requestStorageAccess() function and SimpleStorageHelper#onStorageAccessGranted() callback. You may call SimpleStorageHelper#openFolderPicker() directly. No need to request access anymore:

buttonSelectFolder.setOnClickListener {
    storageHelper.openFolderPicker()
}

storageHelper.onFolderSelected = { requestCode, folder ->
    // tell user the selected path
}

In the future, you can write a file into the selected folder, for example:

val grantedPaths = DocumentFileCompat.getAccessibleAbsolutePaths(this)
val path = grantedPaths.values.firstOrNull()?.firstOrNull() ?: return
val folder = DocumentFileCompat.fromFullPath(this, path, requiresWriteAccess = true)
val file = folder?.makeFile(this, "notes", "text/plain")

from simplestorage.

anggrayudi avatar anggrayudi commented on September 25, 2024 2

v1.5.4 is released.

from simplestorage.

anggrayudi avatar anggrayudi commented on September 25, 2024 1

Oh so SimpleStorageHelper.openFolderPicker() is similar to requestStorageAccess(), but requestStorageAccess is more general (can request access to both folders and files) if I understand correctly?

Basically, if you're not using custom dialog styles, then no need to think much about requestStorageAccess(). You'll understand this function's purpose once you dig into SimpleStorage and SimpleStorageHelper classes.

I would strongly suggest to add both examples you gave above in the README

Sure, I'll do that once v1.5.4 is released.

from simplestorage.

lrq3000 avatar lrq3000 commented on September 25, 2024

And I know it's not the fault of this library. Android's file permission system is insane since Android 11, it doesn't make any sense how hard it is to access storage via scoped storage permissions, most of the time it just plainly fails and there is no documentation even years later to just explain how to do that. It looks like Google wants most apps to be segregated in their own respective storage spaces.

So thank you very much for making this library. I am looking forward to your valuable inputs that will hopefully help me work out a working app.

from simplestorage.

lrq3000 avatar lrq3000 commented on September 25, 2024

Thank you so much, it appears to work! I'm going to revamp my app using the approach you suggested, thank you very much!

The new function would be very helpful, that would be great! But my issue was rather that I did not know how to store and retrieve adequately the permission, your approach fixed it!

Just one question out of curiosity: I notice you suggest to use requestStorageAccess(), why not openFolderPicker()? I thought that FolderPicker was made for this purpose (of selecting a folder tree), no? Or is the FolderPicker only to request read-only access, not write access?

from simplestorage.

lrq3000 avatar lrq3000 commented on September 25, 2024

Oh so SimpleStorageHelper.openFolderPicker() is similar to requestStorageAccess(), but requestStorageAccess is more general (can request access to both folders and files) if I understand correctly?

The new function to query grantedPaths looks awesome, so that we won't need to keep the URIs, it will be great also to debug whether we have permission (instead of trying to infer from getting a returned null object)!

I would strongly suggest to add both examples you gave above in the README, as I think this usecase of requesting access to an external shared folder to allow for file syncing is a pretty common one, and your answers are making this much more easy than I thought. I tried to make it work for days and could not!

Also maybe it would be nice to clarify that DocumentFileCompat can be used to get write access too, as the readme makes it sound like it's only to read files, not to write them.

Thank you once again, your library is providing an invaluable service to all of us poor Android developers!

(You can close this issue whenever you want)

from simplestorage.

lrq3000 avatar lrq3000 commented on September 25, 2024

(I have misunderstood something in my previous message, please check the edited/corrected comment on github)

from simplestorage.

lrq3000 avatar lrq3000 commented on September 25, 2024

This is awesome, thank you so much!

Just a heads up for others who may run into a similar issue, DocumentFile.openOutputStream() does not work anymore if the specified file does not exist.

So this won't work unless the file is created first by another mean:

val preferences2 = PreferenceManager.getDefaultSharedPreferences(appContext)
val path2 = preferences2.getString("path", null)
val path3 = "$path2/testfile.txt"
val file = DocumentFileCompat.fromFullPath(appContext, path3!!, requiresWriteAccess = true) // Don't do it like this, if the file does not exist, trying to openOutputStream() on it will fail. Rather, open the folder, then makeFile with a CreateMode to append.
val out1 = file!!.openOutputStream(appContext, append=true)
try {
    out1!!.write("Some output!".toByteArray(Charsets.UTF_8))
} catch (e: Exception) {
    Log.d("MyApp", "Unable to write test file: " + e.stackTraceToString())
} finally {
    out1?.close()
}

Whereas if we replace the val file line by the following, it will always work (it will create the file if necessary, and if it exists, it will append to it):

val folder = DocumentFileCompat.fromFullPath(appContext, path2!!, requiresWriteAccess = true)
val file = folder?.makeFile(appContext, "testfile.txt", "text/plain", mode=CreateMode.REUSE)

from simplestorage.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.