androidfilestorage-access-framework

How to launch a content uri from a widget


I am trying to make a simple app that will allow users to create widgets out of their pdf files.

  1. The PDF file is choosen by user via SAF File Picker during Widget configuration.
  2. I store the returned Uri (a content uri, which looks like this : content://com.android.providers.downloads.documents/document/msf%3A18) in Shared Preferences.
  3. On widget click, i want to launch a pending intent to open this content Uri in user selected PDF viewer app

I wrote code for all of this, but the pending intent gives a security exception when i try to open it on widget click.

My code for requesting for pdf file using SAF picker:


open  class  EAHActivity:AppCompatActivity(){

    private lateinit var arlPickFile: ActivityResultLauncher<Intent>
    private var callbackPickFile : (Uri) -> Unit = {}
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val requestType = ActivityResultContracts.StartActivityForResult()
        arlPickFile = registerForActivityResult(requestType){
            val result = it?.resultCode?:RESULT_CANCELED;
            if(result!= RESULT_OK) return@registerForActivityResult
            val data = it?.data?.data?:return@registerForActivityResult
            callbackPickFile.invoke(data)
            callbackPickFile = {}
        }
    }
    

    fun requestFile(category: String = Intent.CATEGORY_OPENABLE, filter : String = "application/pdf", onResult:(Uri)->Unit = {}) {
        callbackPickFile = onResult
        val baseIntent = Intent(Intent.ACTION_OPEN_DOCUMENT)
        baseIntent.addCategory(category)
        baseIntent.type = filter
        arlPickFile.launch(baseIntent)

    }

}

My code for pending intent:

 fun getLaunchFilePendingIntent(path:String, ctx: Context):PendingIntent {
            Log.e("TAG", "path:$path" )

            val uri = Uri.parse(path)
            val openIntent = Intent(Intent.ACTION_VIEW)

            openIntent.setDataAndType(uri, "application/pdf")
            openIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
            
            val chooser = Intent.createChooser(openIntent, "Open with")
            val sdk31PlusFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0

            return PendingIntent.getActivity(ctx, 123, chooser, PendingIntent.FLAG_UPDATE_CURRENT or sdk31PlusFlag)

        }

Error:

java.lang.SecurityException: UID 10146 does not have permission to content://com.android.providers.downloads.documents/document/msf%3A18 [user 0]; you could obtain access using ACTION_OPEN_DOCUMENT or related APIs

I am not sure what is going wrong and how to fix it. i am guessing that File Provider/ Content /Document Provider APIs might be needed here, but i do not understand them much.


Solution

  • If you do not directly use an obtained uri then your read permission is ended. So take persistabke uri permission in onActivityResult.