title: saving picture to shared pictures folder android target api 29
body: <p>My goal is to Request picture from Camera app, save it in my app data and also write the same picture to Gallery so if user deletes app it still has the taken pictures (unlike messenger our utility tool pictures are considered highly valuable to user even without the app).</p>
  
  <p>The problem that i'm facing is tightly related to 29 API level witch is the build target (offers to downgrade it not acceptable). </p>
  
  <p>So basically what i get is: </p>
  
  <p><strong>First problem</strong>: Even with <code>Manifest.permission.WRITE_EXTERNAL_STORAGE</code> granted I can't access files constructed with <code>Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)</code> i get IOException (permission denied)</p>
  
  <p><strong>Second problem</strong>: <code>contentResolver.insert(contentUri, contentValues)</code> throws me this on pre Q device (Nokia 8 Android Pie):</p>
  
  <pre><code>java.lang.SecurityException: Permission Denial: writing com.android.providers.media.MediaProvider uri content://media/external/images/media from .... requires android.permission.WRITE_EXTERNAL_STORAGE, or grantUriPermission()
  </code></pre>
  
  <p>If i Run on Android 10 device (emulator in my case) the option using <code>contentResolver.insert(..)</code> works fine. </p>
  
  <p><strong>Main Question</strong> Is how to write picture to android managed gallery folder properly when targeting 29Api level so it would work on pre android 10 devices?</p>
  
  <p><strong>Extra references</strong></p>
  
  <p>My code for writing picture from my App cache storage to gallery for android 10 is: </p>
  
  <pre><code>    fun writePictureToGalleryQ(context: Context, pictureUri: Uri, pictureName: String) {
  
          val contentResolver = context.contentResolver
  
          val relativeLocation = "${Environment.DIRECTORY_PICTURES}${File.separator}WaiJuDuDisAndroid"
  
          val contentValues  = ContentValues().apply {
              put(MediaStore.Images.ImageColumns.DISPLAY_NAME, pictureName)
              put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
              put(MediaStore.Images.ImageColumns.RELATIVE_PATH, relativeLocation)
          }
  
          val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
          var uri: Uri? = null
  
          uri = contentResolver.insert(contentUri, contentValues)
          uri?.let { galleryPartUri -&gt;
  
              val outStream: OutputStream = contentResolver.openOutputStream(galleryPartUri)!!
              val inStream: InputStream = contentResolver.openInputStream(pictureUri)!!
  
              outStream.use {out -&gt;
                  inStream.use { inpt -&gt;
                      inpt.copyTo(out)
                  }
              }
          }
      }
  </code></pre>
  
  <p>P.s. Content providers are set up in manifest as well as needed permissions and file paths xml.  </p>
  
  <p>Code that should do for per Q android versions, but it doesn't   looks like this (Assuming that i already got <code>Manifest.permission.WRITE_EXTERNAL_STORAGE</code>)</p>
  
  <pre><code>    fun writePictureToGalleryLegacy(context: Context, pictureUri: Uri, pictureName: String) {
  
  
          val directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
  
          val correctDir = File("${directory.absolutePath}${File.separator}WaiJuDuDisAndroid")
          correctDir.mkdirs()
  
          val file = File("${correctDir.absolutePath}${File.separator}${pictureUri.lastPathSegment}")
  
          val contentResolver = context.contentResolver
  
          val outStream: OutputStream = file.outputStream()
          val inStream: InputStream = contentResolver.openInputStream(pictureUri)!!
  
          outStream.use {out -&gt;
              inStream.use { inpt -&gt;
                  inpt.copyTo(out)
              }
          }
  
  
          val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.extension)
  
          MediaScannerConnection.scanFile(
                  context,
                  arrayOf(file.absolutePath),
                  arrayOf(mimeType?:"image/*"),
                  null
          )
  
      }
  
  </code></pre>
  
  <p><strong>Update on issue and edit</strong></p>
  
  <p><em>I tweaked my code chunks to be a bit more correct since they actually works.</em></p>
  
  <p>Rebuilding project solved my issue in the end. Not sure what i hate more - Google or myself. </p>
  
  <p>Of course rebuilding project was only part of the solution. </p>
  
  <p>I was having two problems:</p>
  
  <ol>
  <li>Stated by some guy here who removed his answer was that i might be lacking <code>&lt;application... android:requestLegacyExternalStorage="true" ....&gt;</code> </li>
  <li>Some library in my dependencies has <code>android:maxSdkVersion</code> in it's manifest that basically causes to ignore my permission on both Android 10 and Android 9 devices and probably everything starting with Android 4.4.</li>
  </ol>
  
  <p>So accordingly i changed my app manifest:</p>
  
  <pre><code>&lt;manifest&gt;
      &lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/&gt;
  
      &lt;application android:requestLegacyExternalStorage="true" ...&gt;
          ...
      &lt;/application&gt;
  
  &lt;/manifest&gt;
  </code></pre>