Android Question SDK 29 Copy from Camera folder and remove from gallery?

lymey

Active Member
Licensed User
Longtime User
I have an app that works perfectly in Android 9 (<SDK29). Using the Content Chooser I can select any image in the gallery, get the filepath from the URI and copy to my apps folder. I can then delete the chosen file and 'rescan' the gallery to remove the thumbnail.
BUT, with Android 10 (SDK29) I get a permission denied error. The two lines below are from the log:
make file copy: /storage/emulated/0/DCIM/Camera/IMG_20200919_144433_760.jpg
file copy error: android.system.ErrnoException: open failed: EACCES (Permission denied)
I am using 'getsafedirs' in the code and have the 'Write External Storage Permission' in the manifest. I have tried with and without 'requestLegacyExternalStorage':
B4X:
AddManifestText(
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="29"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.
AddManifestText(<uses-permission
android:requestLegacyExternalStorage="true"
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
)

Any ideas on what I have missed?

Also how can we now, remove the the image/thumbnail from the gallery?

Thanks!
 

drgottjr

Expert
Licensed User
Longtime User
#1 you'd better do all your copying quickly, because soon you will have no access to direxternal.
#2 copying via contentchooser does work in 29 with SetApplicationAttribute(android:requestLegacyExternalStorage, true) in the manifest. it took me a while to track that one down. we've been reduced to a workaround until android 11 (see #1 above). did you use inputstream/output stream? i think that's the way you're supposed to go. frankly, you only have to read "avoid direxternal" a few times before you get the picture. i was able to cobble something together to mimic what you describe using sdk29 on my android10 device. it eventually worked with the requestLegacyExternalStorage in the manifest.
#3 good luck with the deleting.
 
Upvote 0

Alex_197

Well-Known Member
Licensed User
Longtime User
You can use
B4X:
    Private rp As RuntimePermissions
    Private VideoFileDir As String
    
    VideoFileDir = rp.GetSafeDirDefaultExternal("")

for deleting
B4X:
If File.Exists(VideoFileDir,FileName) Then
            
            Del=File.Delete(VideoFileDir,FileName)           
            Log(Del)
            
End If
 
Upvote 0

lymey

Active Member
Licensed User
Longtime User
Thanks to both of you.
With a combination of 'rp.getsafedefaultexternal' and 'input/output stream' this seems to work in Android 10 without needing the 'requestLegacyExternalStorage' in the manifest:
B4X:
Dim uri As String = intent.RunMethod("getParcelableExtra", Array("android.intent.extra.STREAM"))
...
Dim Infile As InputStream = File.OpenInput("ContentDir" ,uri)
Dim OutFile As OutputStream = File.OpenOutput(SafeDefaultFileDirectory, my_filename, False)
File.Copy2(Infile, OutFile)

The next problem is how to remove the file from gallery?
 
Upvote 0

lymey

Active Member
Licensed User
Longtime User
This seems to work for SDK >=29 (Android 10, I haven't even attempted Android 11 yet) and SDK < 29 using Erels AddBitmapToGallery code as a basis for the deletion:
B4X:
                  If ph.SdkVersion < 29 Then
                      Try
                        File.Delete(chosen_directory, chosen_filename)
                        'mediascanner for sdk < 29
                        Dim context As JavaObject
                        context.InitializeContext
                        Dim MimeType As String
                        If chosen_filename.Contains(".jpg") Or chosen_filename.Contains(".jpeg") Then
                            MimeType="image/jpg"
                        End If
                        If chosen_filename.Contains(".png")  Then
                            MimeType="image/png"
                        End If
                        Dim FilePath As String = File.Combine(chosen_directory,chosen_filename)
                        Dim MediaScannerConnection As JavaObject
                        MediaScannerConnection.InitializeStatic("android.media.MediaScannerConnection")
                        Dim interface As Object = MediaScannerConnection.CreateEventFromUI("android.media.MediaScannerConnection.OnScanCompletedListener", "ScanCompleted", _
                        Null)
                        MediaScannerConnection.RunMethod("scanFile", Array(context, Array As String(FilePath), Array As String(MimeType), interface))
                        Wait For ScanCompleted_Event (MethodName As String, Args() As Object)
                  
                        Catch
                          Log(LastException.Message)
                          Wait For (xui.MsgboxAsync("Sorry, the file/thumbnail can't be removed!", "Move From Gallery")) Msgbox_Result (mResult As Int)
                          Return
                        End Try
                    Else
                        Try
                        'SdkVersion >= 29 Then
                        Dim cr As ContentResolver
                        cr.Initialize("cr")
                        Dim MediaStoreImagesMedia As JavaObject
                        MediaStoreImagesMedia.InitializeStatic("android.provider.MediaStore.Images$Media")
                        Dim EXTERNAL_CONTENT_URI As Uri = MediaStoreImagesMedia.GetField("EXTERNAL_CONTENT_URI")
                        cr.Delete(EXTERNAL_CONTENT_URI, "_display_name = ?", Array As String(chosen_filename))
                        If File.Exists(chosen_directory, chosen_filename) Then
                            Log("SDK 29 gallery delete failed")
                        End If
                         
                        Catch
                            Log("SDK 29 ERROR: " & LastException.Message)
                            Wait For (xui.MsgboxAsync("Sorry, the file/thumbnail can't be removed!", "Move From Gallery")) Msgbox_Result (mResult As Int)
                            Return
                        End Try
                    End If
 
Upvote 0
Top