Search code examples
androidandroid-intentandroid-permissionsandroid-11storage-access-framework

Image not opening in other apps via Intent.ACTION_VIEW in android 11


I am downloading image file from the server and storing it on the device. When file is stored I want to show this image in any apps which support this mimetype. I am able to store the image in the storage but unable to open the file. This is my code.

private fun savePhotoToExternalStorage(displayName: String, bmp: Bitmap, mimeType:String): Boolean {
    LogUtil.d(TAG, "savePhotoToExternalStorage: ")
    
    val imageCollection = sdk29AndUp {
        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    } ?: MediaStore.Images.Media.EXTERNAL_CONTENT_URI

    val contentValues = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, displayName)
        put(MediaStore.Images.Media.MIME_TYPE, mimeType)
        put(MediaStore.Images.Media.WIDTH, bmp.width)
        put(MediaStore.Images.Media.HEIGHT, bmp.height)

    }
    return try {
        context.contentResolver.insert(imageCollection, contentValues)?.also { uri ->
            context.contentResolver.openOutputStream(uri).use { outputStream ->
                if(!bmp.compress(Bitmap.CompressFormat.JPEG, 95, outputStream)) {
                        
                    LogUtil.e(TAG, "savePhotoToExternalStorage: Exception")
                }

               
                val file = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), displayName)



                val shareUri =if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)

                FileProvider.getUriForFile(
                        context, context.packageName + ".fileprovider", file)
                else
                    Uri.fromFile(file)
                LogUtil.d(TAG, "savePhotoToExternalStorage: shareuri: $shareUri")

                Log.d(TAG, "savePhotoToExternalStorage: ${shareUri.authority}")

                val intent = Intent(Intent.ACTION_VIEW)
                    .setDataAndType(shareUri, mimeType)
                    .putExtra(Intent.EXTRA_STREAM, shareUri)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

                LogUtil.d(TAG, "savePhotoToExternalStorage: intent: $intent")

                val resolvedInfoActivities: List<ResolveInfo> =
                    context.packageManager.queryIntentActivities(
                        intent,
                        PackageManager.MATCH_DEFAULT_ONLY
                    )
                for (ri in resolvedInfoActivities) {
                    Log.e(TAG, "resolvedInfoActivities: $ri", )
                    context.grantUriPermission(
                        ri.activityInfo.packageName,
                        shareUri,
                        Intent.FLAG_GRANT_READ_URI_PERMISSION
                    )
                }

                try {
                    
                    
                    context.startActivity(Intent.createChooser(intent, "Open with").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION))
                } catch (e: ActivityNotFoundException) {
                   
                    e.printStackTrace()
                    Log.e(TAG, "savePhotoToExternalStorage: ${e.message}")
                }

            }
        }
        true
    } catch(e: IOException) {
        Log.e(TAG, "savePhotoToExternalStorage: ${e.message} ")
        e.printStackTrace()
        false
    }catch (e : Exception){
        Log.e(TAG, "savePhotoToExternalStorage: ${e.message}", )
        e.printStackTrace()
        false
    }
}

I have also created the fileprovider.

fileprovider.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
    name="files_root"
    path="Android/data/${applicationId}"/>
<external-path
    name="external_storage_root"
    path="."/>

<external-path name="external_files" path="."/>

<files-path
    name="int_files"
    path="." />
<external-files-path
    name="ext_files"
    path="." />
<cache-path
    name="int_cache"
    path="." />
<external-cache-path
    name="ext_cache"
    path="." />
</paths>

Add provider in AndroidManifest for this provider AndroidManifest.xml

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/fileprovider" />
    </provider>

This code open the intent chooser and when I select an app it shows Media not found error.


Solution

  •           val file = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), displayName)
    

    You will not use the File class here. Not needed at all.

    Use the uri directly.

    So change

    val shareUri = .... - a lot of wrong code-
    

    to:

    val shareUri = uri.
    

    The point is that you already have a nice uri so trying to build up another one (and a wrong one) is not needed.