Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kivy filechooser by plyer not working properly #683

Open
guirodrigueslima opened this issue Jun 9, 2022 · 5 comments
Open

Kivy filechooser by plyer not working properly #683

guirodrigueslima opened this issue Jun 9, 2022 · 5 comments

Comments

@guirodrigueslima
Copy link

Hello everyone from the kivy community, all the problems I've had so far I've been able to solve through the community, I'm very grateful for that.

I'm developing an app in kivy, everything is working correctly, but I have a specific problem when I'm using the native android selector (filechooser by plyer).

I'm using:
kivy==2.1.0
plyer==2.0.0

I need to select an image (.png, .jpg...) when I browse the native android selector and select an image file I get the path correctly ["/storage/.../image.jpg"]. But when I click on the "gallery" and select the image, I get an empty list [[]]. I will show the problem in detail.

WhatsApp.Video.2022-06-09.at.16.56.01.mp4

Note that in the first case, I selected the images that are appearing in "recent" on the first screen of the android selector, it also works if I browse other folders in that same selector. So I get the correct path of the file ["/storage/.../IMG-20220530-WA0007.jpg"].

WhatsApp.Video.2022-06-09.at.16.55.55.mp4

Now in the second case, when I select the "Gallery" in the suggestions, the selector opens another screen and when I select the desired image I get an empty list [[]]. This problem also happened on three other smartphones.

Anyone had a similar problem? is there any way to solve this problem? can i remove these suggestions from the selector?

image

Where can I find the plyer/filechooser module in my .buildozer file?

I will apologize because my app is being developed in Portuguese. Thanks !!!

@guirodrigueslima
Copy link
Author

I'm complementing the question with a part of my code:

filechooser.open_file(on_selection=self.path ,multiple = False,filters=[["Image", "*png", "*jpg","*jpeg"]])

@RobertFlatt
Copy link

Plyer is not well supported, I don't think filechooser works on newer Android versions.
The Plyer code is here https://github.com/kivy/plyer/blob/master/plyer/platforms/android/filechooser.py

On newer Android versions shared storage is not a file system, a Python app can't get a filepath to open()
https://github.com/Android-for-Python/Android-for-Python-Users#android-storage

Here are two examples containing Android Chooser usage without using Plyer
https://github.com/Android-for-Python/share_send_example
https://github.com/Android-for-Python/shared_storage_example
They depend on copying the selected file (with Java) to private storage where it can be opened by Python.

@Neizvestnyj
Copy link
Contributor

Its will help you. https://github.com/Neizvestnyj/cross-platform-image-picker/blob/master/main.py Use file_path from my solution (its local file copy)

@guirodrigueslima
Copy link
Author

Hello, @RobertFlatt and @Neizvestnyj, thanks for the suggestions.
today i started to analyze the filechooser source code and developed a solution. This solution only works for selecting an image file, but it can be easily modified for other files. Now I can select images straight from android's native selector and gallery explorer. I was also able to filter the native selector to image files only, this didn't work for plyer. Below is a summary of my code, this example needs to be inserted into your script of choice and calling the def button_select_photo(self): function by a button. This example works on android (by startActivityForResult) and on Windows (by Plyer).

from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy import platform

from kivymd.app import MDApp
from plyer import filechooser

import jnius
from jnius import autoclass
from jnius import cast

path = []

if platform == "android":

    from android.permissions import request_permissions, Permission
    from android import activity, mActivity
    from jnius import autoclass
    request_permissions([Permission.WRITE_EXTERNAL_STORAGE,Permission.READ_EXTERNAL_STORAGE])

class MyScreen(Screen):

    def button_select_photo(self):
        if platform == "android":
            Intent = autoclass('android.content.Intent')
 
            self.intent = Intent(Intent.ACTION_GET_CONTENT)
            self.intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, False) #select multiple =  False  
            self.intent.setType('image/*') #only image
                    
            self.chooser = Intent.createChooser(self.intent, None)
                    
            REQUEST_CODE = 0 #identification code, can be any value, this value will be returned in def intent_back
                                       
            mActivity.startActivityForResult(self.chooser, REQUEST_CODE)
                    
        else:
                    
            filechooser.open_file(on_selection=self.path ,multiple = False,filters=[["Image","*png", "*jpg","*jpeg"]])

    def path(self,selection):
        global path    
        path = selection
                    
 class MyMainApp(MDApp):

    def build(self):
        if platform == "android":
            activity.bind(on_activity_result=self.intent_callback)
        kv = Builder.load_file("main.kv")
        return kv

    def intent_callback(self, requestCode, resultCode, intent):
        global path
        #print(requestCode, resultCode, intent)
        if resultCode == -1: # Activity.RESULT_OK (indicates that the file has been selected)
            if requestCode == 0: #activity return identification code, necessary for those who use more than one activity operation
                
                path = []

                data = intent.getData()
                data_authority = data.getAuthority()
                data_scheme = data.getScheme().lower()
                
                print(data_authority)
                print(data_scheme)
                
                if data_authority == "com.android.providers.media.documents": #Image selected by native selector
                    DocumentsContract = autoclass('android.provider.DocumentsContract')
                    IMedia = autoclass('android.provider.MediaStore$Images$Media')
                    
                    file_id = DocumentsContract.getDocumentId(data)
                    file_name = file_id.split(':')[1]
                    file_type = IMedia.EXTERNAL_CONTENT_URI
                    selection = '_id=?'
                    
                    if data_scheme == 'content':
                        cursor = mActivity.getContentResolver().query(
                            file_type, ["_data"], selection,
                            [file_name], None
                        )

                        idx = cursor.getColumnIndex("_data")
                        if idx != -1 and cursor.moveToFirst():
                            path = cursor.getString(idx)

                else: #Image selected by gallery
                    if data_scheme == 'content':
                        #print(data.getPath())
                        #print(data.toString())
                        path = [data.getPath().replace("/raw/","")] #replace("/raw/","") is necessary as it returns the "raw" path dedicated to the developer, replace is not needed for the final version. It is also possible to treat in other ways.
                
                print(path)
                
if __name__ == "__main__":
    MyMainApp().run()

I know that this solution is not the most ideal, but it solves many problems. Mainly for those who need to select a photo and get the path.
I will leave this issue open for possible improvement.
Thanks

@guirodrigueslima
Copy link
Author

I am attaching the video for better understanding. Notice in the first case that I selected the photo in android's native selector. And in the second case I opened the gallery and selected the photo from it.

WhatsApp.Video.2022-06-14.at.22.27.13.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants