Android Question Get a image from gallery and crop it in SDK = 26

asales

Expert
Licensed User
Longtime User
I use this code below to open the gallery, get a image and crop using the internal tool to crop.
I made a few change to uses the in the SDK = 26, like runtime permissions.

The old function to crop the image uses "GetPathFromContentResult" (that don't works in SDK = 26, works fine until SDK = 23) and @Erel says "it is a mistake to use this sub", in this post:
https://www.b4x.com/android/forum/t...s-returned-from-contentchooser.39313/#content

I tried several changes in code of the cropPicture sub to work, after select the image in gallery, but without success.

How can I fix this problem?

Thanks in advance.

B4X:
Sub Button1_Click
    Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_READ_EXTERNAL_STORAGE)
End Sub

Sub Activity_PermissionResult (Permission As String, Result As Boolean)
    If Permission = Starter.rp.PERMISSION_READ_EXTERNAL_STORAGE Then GetImage
End Sub

Sub GetImage
    cc.Show("image/*", "Select Photo")
End Sub

Sub cc_Result (Success As Boolean, Dir As String, FileName As String)
    If Success Then
        'If show the image in ImageView, without crop, works
        ImgPhoto.Bitmap = LoadBitmapSample(Dir, FileName, ImgPhoto.Width, ImgPhoto.Height)
        'If I try to crop, don't works in SDK = 26
        cropPicture(FileName)
    End If
End Sub

Sub cropPicture(SelectedPhoto As String)
    Dim i As Intent
    i.Initialize("com.android.camera.action.CROP", ParseUri("file://" & GetPathFromContentResult(SelectedPhoto)))
    i.SetType("image/*")
    i.PutExtra("crop", "true")
    i.PutExtra("aspectX", 1)
    i.PutExtra("aspectY", 1)
    i.PutExtra("output", ParseUri("file://" & File.Combine(Starter.rp.GetSafeDirDefaultExternal(""), "photo1.jpg")))
    StartActivityForResult(i)
End Sub

Sub ParseUri(FileName As String) As Object
    Dim r As Reflector
    Return r.RunStaticMethod("android.net.Uri", "parse", Array As Object(FileName), Array As String("java.lang.String"))
End Sub

Sub StartActivityForResult(i As Intent)
    Dim jo As JavaObject = GetBA
    ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
    jo.RunMethod("startActivityForResult", Array As Object(ion, i))
End Sub

Sub GetBA As Object
    Dim jo As JavaObject
    Dim cls As String = Me
    cls = cls.SubString("class ".Length)
    jo.InitializeStatic(cls)
    Return jo.GetField("processBA")
End Sub

Sub ion_Event (MethodName As String, Args() As Object) As Object
    If Args(0) = -1 Then
        ImgPhoto.Bitmap = LoadBitmapSample(Starter.rp.GetSafeDirDefaultExternal(""), "photo1.jpg", ImgPhoto.Width, ImgPhoto.Height)
    End If
    Return Null
End Sub
 

asales

Expert
Licensed User
Longtime User
I see this thread, but it to share a file.
I want to pick a image from gallery and crop.

I try to use the "CreateFileProviderUri", but don't works neither:
B4X:
Sub cropPicture(Dir As String, SelectedPhoto As String)
    Dim i As Intent
    i.Initialize("com.android.camera.action.CROP", CreateFileProviderUri(Dir, SelectedPhoto))
    i.SetType("image/*")
    i.PutExtra("crop", "true")
    i.PutExtra("aspectX", 1)
    i.PutExtra("aspectY", 1)
    i.PutExtra("output", CreateFileProviderUri(Starter.rp.GetSafeDirDefaultExternal(""), "photo1.jpg"))
    StartActivityForResult(i)
End Sub
 
Upvote 0

asales

Expert
Licensed User
Longtime User
This is the log and the error with the sub cropPicture:
B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (OnActivityResult)
running waiting messages (1)
Success = true, Dir = ContentDir, FileName = content://com.android.providers.media.documents/document/image%3A76400
main_vv2 (java line: 430)
java.lang.reflect.InvocationTargetException
   at java.lang.reflect.Method.invoke(Native Method)
   at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:131)
   at b4a.example.fileprovider.main._vv2(main.java:430)
   at b4a.example.fileprovider.main._vv4(main.java:466)
   at b4a.example.fileprovider.main._cc_result(main.java:407)
   at java.lang.reflect.Method.invoke(Native Method)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:191)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
   at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:865)
   at anywheresoftware.b4a.BA$4.run(BA.java:563)
   at anywheresoftware.b4a.BA.setActivityPaused(BA.java:437)
   at b4a.example.fileprovider.main$ResumeMessage.run(main.java:306)
   at android.os.Handler.handleCallback(Handler.java:751)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6123)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /ContentDir/content:/com.android.providers.media.documents/document/image%3A76400
   at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:738)
   at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:417)
   ... 19 more
 
Upvote 0

asales

Expert
Licensed User
Longtime User
I guess that you are testing it on a Android 6- device, right?

It is better to only use FileProvider with Phone.SdkVersion >= 24 (Android 7).

I tested in devices with Android 4.4, 6.0 and 7.0 and I get the same error.

My project is in attached.
Is based in FileProviderShare and I changed to select the photo in gallery and crop.
If I only select the photo and show in imageview, works. The problem is in crop function.
 

Attachments

  • FileProviderShare+Crop.zip
    19.7 KB · Views: 313
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
1. It is a mistake to write Starter.rp.GetSafeDirDefaultExternal("") multiple times. Use a process global variable with the target dir.
2. You can only share files that are stored in the folder you set in the manifest file. In your case it is:
B4X:
Starter.rp.GetSafeDirDefaultExternal("shared")

You need to copy the selected file to this folder and then you will be able to share it with other apps.
 
Upvote 0

asales

Expert
Licensed User
Longtime User
I tried, but until now I don't know what am I wrong.
1. It is a mistake to write Starter.rp.GetSafeDirDefaultExternal("") multiple times. Use a process global variable with the target dir.
I created this variable in Starter service:

B4X:
Public sharedFolder As String

Sub Service_Create
    sharedFolder = rp.GetSafeDirDefaultExternal("shared")
End Sub

2. You can only share files that are stored in the folder you set in the manifest file.
My manifest:
B4X:
AddApplicationText(
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="$PACKAGE$.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
)
CreateResource(xml, provider_paths,
   <external-files-path name="name" path="shared" />
)

You need to copy the selected file to this folder and then you will be able to share it with other apps.
I tried to copy the file before open with the crop tool, but don't works.
In this code below I get this message in log: onActivityResult: wi is null

B4X:
Sub cropPicture(Dir As String, SelectedPhoto As String)
   Dim i As Intent
   'copy the file to crop
   File.Copy(Dir, SelectedPhoto, Starter.sharedFolder, "photo1.jpg")
   i.Initialize("com.android.camera.action.CROP", CreateFileProviderUri(Starter.sharedFolder, "photo1.jpg"))
   i.SetType("image/*")
   i.SetComponent(CreateFileProviderUri(Starter.sharedFolder, "photo1.jpg"))
   i.PutExtra("crop", "true")
   i.PutExtra("aspectX", 1)
   i.PutExtra("aspectY", 1)
   i.PutExtra("output", CreateFileProviderUri(Starter.sharedFolder, "photo2.jpg"))
   StartActivityForResult(i)
End Sub

Sub cc_Result (Success As Boolean, Dir As String, FileName As String)
   If Success Then
       cropPicture(Dir, FileName)
   End If
End Sub

Sub StartActivityForResult(i As Intent)
    Dim jo As JavaObject = GetBA
    ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
    jo.RunMethod("startActivityForResult", Array As Object(ion, i))
End Sub

Sub GetBA As Object
    Dim jo As JavaObject
    Dim cls As String = Me
    cls = cls.SubString("class ".Length)
    jo.InitializeStatic(cls)
    Return jo.GetField("processBA")
End Sub

Sub ion_Event (MethodName As String, Args() As Object) As Object
    If Args(0) = -1 Then
        Activity.SetBackgroundImage(LoadBitmapSample(Starter.sharedFolder, "photo2.jpg", 100%x, 100%y))
    End If
    Return Null
End Sub

Sub CreateFileProviderUri (Dir As String, FileName As String) As Object
    Dim FileProvider As JavaObject
    Dim context As JavaObject
    context.InitializeContext
    FileProvider.InitializeStatic("android.support.v4.content.FileProvider")
    Dim f As JavaObject
    f.InitializeNewInstance("java.io.File", Array(Dir, FileName))
    Return FileProvider.RunMethod("getUriForFile", Array(context, Application.PackageName & ".provider", f))
End Sub
 
Upvote 0

asales

Expert
Licensed User
Longtime User
Upload a small example with the updated code.
Here is.

To select and show a photo of gallery in imageview, works.
If I try to select and crop, don't works and I get this message in log: "onActivityResult: wi is null"
 

Attachments

  • FileProviderShare+Crop.zip
    19.7 KB · Views: 333
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
A good test is to change StartActivityForResult with StartActivity. You will see this crash:

java.lang.RuntimeException: android.content.ActivityNotFoundException: Unable to find explicit activity class {content://b4a.example.provider/name/photo1.jpg}; have you declared this activity in your AndroidManifest.xml?

This happens because this line is wrong:
B4X:
i.SetComponent(CreateFileProviderUri(Starter.sharedFolder, "photo1.jpg"))
Remove it.

I don't think that it is a good idea to use this crop intent at all as this is not a standard Android feature.

With this code it almost works:
B4X:
Sub cropPicture(Dir As String, SelectedPhoto As String)
   Dim i As Intent
   File.Copy(Dir, SelectedPhoto, Starter.sharedFolder, "photo1.jpg")
   Dim source As Object = CreateFileProviderUri(Starter.sharedFolder, "photo1.jpg")
   i.Initialize("com.android.camera.action.CROP", source)
   i.SetType("image/*")
   '
   i.PutExtra("crop", "true")
   i.PutExtra("aspectX", 1)
   i.PutExtra("aspectY", 1)
   Dim uri As Object = CreateFileProviderUri(Starter.sharedFolder, "photo2.jpg")
   Dim ctxt As JavaObject
   ctxt.InitializeContext
   ctxt.RunMethod("grantUriPermission", Array("com.android.systemui", uri, 1))
   ctxt.RunMethod("grantUriPermission", Array("com.android.systemui", source, 1))
   i.PutExtra("output", ctxt)
   i.Flags = 1
   StartActivityForResult(i)
End Sub
The camera app shows a message that it cannot edit the image.
 
Upvote 0
Top