Skip to content

Documentation: example using startActivityForResult with bind(on_activity_result=) #388

@arlowhite

Description

@arlowhite

I'd like to contribute some documentation. This code opens the Android Photo Gallery and gets the filepath of the selected image.
It took me a few hours to figure out how to do this. The only discussion on it I could find was here:
https://groups.google.com/forum/#!msg/kivy-users/bjsG2j9bptI/-Oe_aGo0newJ

I think it would helpful if an example like this was in the official documentation somewhere. However, I'm not sure if it should be in the p4a or pyjnius docs.
http://python-for-android.readthedocs.org/en/latest/examples/
http://pyjnius.readthedocs.org/en/latest/android.html#accessing-the-activity

I'd be willing to create the documentation and do a pull request, just let me know:

  1. Where the documentation should go
  2. Any problems with the code below that sets a bad example or other things to change in the example

Just realized, should I activity.unbind at the end of the on_activity_result function?

from kivy.logger import Logger
from kivy.clock import Clock

from jnius import autoclass
from jnius import cast

# python-for-android provides this
from android import activity

PythonActivity = autoclass('org.renpy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')

# Value of MediaStore.Images.Media.DATA
MediaStore_Images_Media_DATA = "_data"

# Custom request codes
RESULT_LOAD_IMAGE = 1

Activity = autoclass('android.app.Activity')
# Activity is only used to get these codes. Could just hardcode them.
    # /** Standard activity result: operation canceled. */
    # public static final int RESULT_CANCELED    = 0;
    # /** Standard activity result: operation succeeded. */
    # public static final int RESULT_OK           = -1;
    # /** Start of user-defined activity results. */
    # Not sure what this means
    # public static final int RESULT_FIRST_USER   = 1;

def user_select_image(callback):
    """Open Gallery Activity and call callback with absolute image filepath of image user selected.
    None if user canceled.
    """

    # PythonActivity.mActivity is the instance of the current Activity
    # BUT, startActivity is a method from the Activity class, not from our
    # PythonActivity.
    # We need to cast our class into an activity and use it
    currentActivity = cast('android.app.Activity', PythonActivity.mActivity)

    # Forum discussion: https://groups.google.com/forum/#!msg/kivy-users/bjsG2j9bptI/-Oe_aGo0newJ
    def on_activity_result(request_code, result_code, intent):
        if request_code != RESULT_LOAD_IMAGE:
            Logger.warning('user_select_image: ignoring activity result that was not RESULT_LOAD_IMAGE')
            return

        if result_code == Activity.RESULT_CANCELED:
            Clock.schedule_once(lambda dt: callback(None), 0)
            return

        if result_code != Activity.RESULT_OK:
            # This may just go into the void...
            raise NotImplementedError('Unknown result_code "{}"'.format(result_code))

        selectedImage = intent.getData();  # Uri
        filePathColumn = [MediaStore_Images_Media_DATA]; # String[]
        # Cursor
        cursor = currentActivity.getContentResolver().query(selectedImage,
                filePathColumn, None, None, None);
        cursor.moveToFirst();

        # int
        columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        # String
        picturePath = cursor.getString(columnIndex);
        cursor.close();
        Logger.info('android_ui: user_select_image() selected %s', picturePath)

        # This is possibly in a different thread?
        Clock.schedule_once(lambda dt: callback(picturePath), 0)

    # See: http://pyjnius.readthedocs.org/en/latest/android.html
    activity.bind(on_activity_result=on_activity_result)

    intent = Intent()

    # http://programmerguru.com/android-tutorial/how-to-pick-image-from-gallery/
    # http://stackoverflow.com/questions/18416122/open-gallery-app-in-android
    intent.setAction(Intent.ACTION_PICK)
    # TODO internal vs external?
    intent.setData(Uri.parse('content://media/internal/images/media'))
    # TODO setType(Image)?

    currentActivity.startActivityForResult(intent, RESULT_LOAD_IMAGE)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions