miguelbcr / RxPaparazzo

RxJava extension for Android to take images using camera and gallery and pick files up
Apache License 2.0
465 stars 53 forks source link

Picking images in Android Q #104

Open BorisLaskov opened 5 years ago

BorisLaskov commented 5 years ago

Picking images from gallery in Android Q does not work (probably due to the changes regarding external storage access). Tested on the emulator with Android Q.

JakubObornik commented 5 years ago

Picking images from gallery in Android Q does not work (probably due to the changes regarding external storage access). Tested on the emulator with Android Q.

Quick fix could be add this line to your manifest: <application android:requestLegacyExternalStorage="true" ... >

or follow guidelines as mention there: https://developer.android.com/training/data-storage/files/external-scoped

droidluv commented 5 years ago

@JakubObornik can you explain on the guidelines to follow with RxPapparazo? I have no idea how to fix this and using android:requestLegacyExternalStorage="true" doesn't help

JakubObornik commented 5 years ago

@droidluv You have to modify storage scope for saving pictures using RxPaparazzo, because in default it's counting on the external store. Enabled request legacy external storage should fix this problem, are you sure you have the same problem as 145k0v mention? (check your logcat)

Problem is described in "Opt out of scoped storage" part of the documentation

droidluv commented 5 years ago

@JakubObornik sorry android:requestLegacyExternalStorage="true" did actually work, in my panic I didn't realize it, thanks for the support, scoped storage seems like a nightmare, because I was having issues just reading a file from a filepath even though I have both read and write external permissions, and the 'quickfix' helps for now, but Google is going to enforce this strictly from the next Android versions and its going to create waves of nightmares for developer's.

Just an extra question, wouldn't working with scoped storage require us to always copy the content however large because the FileDescriptor returning an InputStream only?

Like I am assuming when we get the uri from ACTION_GET_CONTENT or ACTION_OPEN_DOCUMENT for suppose mime types image/ and extra mime types video/

the onActivityResult gives use the uri and from the uri we can do the following val parcelFileDescriptor: ParcelFileDescriptor = contentResolver.openFileDescriptor(uri, "r")

but from here on out can I directly access the media content atleast just to read? Or do I have to write it to a temp file(which might take a long time if its a large video file) in my app directory and proceed? Would like some enlightenment on how I can proceed in a fast manner.

@miguelbcr any plans on making things easier for people using the scoped storage? Because Android 11 is going to strictly enforce this and there will be no other workaround like android:requestLegacyExternalStorage to rely on

JakubObornik commented 5 years ago

@JakubObornik sorry android:requestLegacyExternalStorage="true" did actually work, in my panic I didn't realize it, thanks for the support, scoped storage seems like a nightmare, because I was having issues just reading a file from a filepath even though I have both read and write external permissions, and the 'quickfix' helps for now, but Google is going to enforce this strictly from the next Android versions and its going to create waves of nightmares for developer's.

Just an extra question, wouldn't working with scoped storage require us to always copy the content however large because the FileDescriptor returning an InputStream only?

Like I am assuming when we get the uri from ACTION_GET_CONTENT or ACTION_OPEN_DOCUMENT for suppose mime types image/ and extra mime types video/

the onActivityResult gives use the uri and from the uri we can do the following val parcelFileDescriptor: ParcelFileDescriptor = contentResolver.openFileDescriptor(uri, "r")

but from here on out can I directly access the media content atleast just to read? Or do I have to write it to a temp file(which might take a long time if its a large video file) in my app directory and proceed? Would like some enlightenment on how I can proceed in a fast manner.

@miguelbcr any plans on making things easier for people using the scoped storage? Because Android 11 is going to strictly enforce this and there will be no other workaround like android:requestLegacyExternalStorage to rely on

You can copy the media file or just use MediaStore instead of use ExternalFileDir (everything is explained in documentation (check the table in the first part of doc).

And about the second question for Miquel, I think he already works on the new version, but it is not publicly released yet (check the source code, there is "2.x-SNAPSHOT" version for maven repository)

droidluv commented 5 years ago

@JakubObornik thanks for your advice the thing is the documentation is not clear how I can access a file from the retrieved uri for example I understand this step

  val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
    addCategory(Intent.CATEGORY_OPENABLE)
    type = "image/*"
}
startActivityForResult(intent, READ_REQUEST_CODE)

and in onActivityResult I have

   override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
     if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        resultData?.data?.also { uri ->
        Log.i(TAG, "Uri: $uri")
        showImage(uri)
       }
    }
  }

the showImage(uri) method is

   val parcelFileDescriptor: ParcelFileDescriptor = contentResolver.openFileDescriptor(uri, "r")
    val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor

and in the documentation they show how to retrieve a bitmap like

val image: Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
parcelFileDescriptor.close();

where image is a Bitmap, this all fine but how can I access the actual file directly for read? an filepath I retrieve from the url is valid but I'll get an FileNotFound exception with an access denied error just like how they mentioned in the documentation, how can I access the media file

how can I identify whether the retrieved file is a video or image mime type? Thanks for all your help, sorry for bothering you, if there is a detailed documentation or article that would be helpful

ikurek commented 4 years ago

I've run across this issue today. Using android:requestLegacyExternalStorage="true" is just an override, and library should be updated to use recommended file access method, most probably openFileDescriptor()

Shubham178046 commented 3 years ago

if i capture image or pick image from gallery using RxPaparazzo in android 11 device than I got Error 1 Exception Occurred message

Vij3n commented 3 years ago

Took a while to find an example for replacement of the deprecated MediaStore.Images.Media.DATA. Finally found the suggestion from @droidluv above which worked - thanks @droidluv. Copying my working onActivityResult method here incase anyone else needs it.

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.d("Event: ","onActivityResult")

        if (requestCode == PICK_IMAGE_CODE && data != null && resultCode == RESULT_OK){
            Log.d("Event: ","onActivityResult is satisfied")
            val selectedImage = data.data
            val parcelFileDescriptor: ParcelFileDescriptor? = contentResolver.openFileDescriptor(selectedImage!!,"r")
            val fileDescriptor: FileDescriptor = parcelFileDescriptor!!.fileDescriptor
            val image:Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
            parcelFileDescriptor.close()

            ivImagePerson.setImageBitmap(image)
        }
    }