Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an Android Activity Context in python with pyjnius

I'm working on importing braintrees drop-in UI payment method into my python kivy app with the following code.

from jnius import autoclass
from jnius import cast
from android import activity

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

DropInRequest = autoclass('com.braintreepayments.api.dropin.DropInRequest')

#Global instance
instance = None
REQUEST = 1
RESULT_OK = 1

def onBraintreeSubmit(token):
    global instance

    def on_activity_result(request, response, data):
        global instance
        if request == REQUEST:
            print response
            if response == RESULT_OK:
                result = instance.getParcelableExtra(instance.EXTRA_DROP_IN_RESULT)
                nonce = result.getPaymentMethodNonce()
                print nonce
                return nonce

    activity.bind(on_activity_result=on_activity_result)
    instance = DropInRequest()
    instance.clientToken(token)
    intent = instance.getIntent(activity.this)
    PythonActivity.mActivity.startActivityForResult(intent,REQUEST)

Which is trying to mimic this Java code

DropInRequest dropInRequest = new DropInRequest()
    .clientToken(mClientToken);
startActivityForResult(dropInRequest.getIntent(context), DROP_IN_REQUEST);

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == DROP_IN_REQUEST) {
        if (resultCode == Activity.RESULT_OK) {
            DropInResult result = data.getParcelableExtra(DropInResult.EXTRA_DROP_IN_RESULT);
            String paymentMethodNonce = result.getPaymentMethodNonce().getNonce();
            // send paymentMethodNonce to your server
        } else if (resultCode == Activity.RESULT_CANCELED) {
            // canceled
        } else {
            // an error occurred, checked the returned exception
            Exception exception = (Exception) data.getSerializableExtra(DropInActivity.EXTRA_ERROR);
        }
    }
}

My problem is I need to send a Context to the getIntent function of the DropInRequest class but I can't figure out how to make an Activity Context with python-for-andriod and pyjnius. Java method of getIntent below.

public Intent getIntent(Context context) {
    return new Intent(context, DropInActivity.class)
            .putExtra(EXTRA_CHECKOUT_REQUEST, this);
}

I think I need to include this to my manifest and use com.braintreepayments.api.BraintreeBrowserSwitchActivity as my activity but I'm not sure how to get the context from it.

<activity android:name="com.braintreepayments.api.BraintreeBrowserSwitchActivity"
    android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="${applicationId}.braintree" />
    </intent-filter>
</activity>

Which I think should call this class which is a BrowserSwitchActivity which I would need to get the context from the BrowserSwitchActivity

package com.braintreepayments.api;

import com.braintreepayments.browserswitch.BrowserSwitchActivity;

/**
 * Helper Activity that captures the response when browser switch completes.
 */
public class BraintreeBrowserSwitchActivity extends BrowserSwitchActivity {
}

Which ends up here which extends the class onto an Activity Class

package com.braintreepayments.browserswitch;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;

/**
 * <a href="https://developer.android.com/guide/topics/manifest/activity-element.html#lmode">singleTask</a>
 * Activity used to receive the response from a browser switch. This Activity contains no UI and
 * finishes during {@link Activity#onCreate(Bundle)}.
 */
public class BrowserSwitchActivity extends Activity {

    private static Uri sReturnUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        sReturnUri = null;
        if (getIntent() != null && getIntent().getData() != null) {
            sReturnUri = getIntent().getData();
        }

        finish();
    }

    /**
     * @return the uri returned from the browser switch, or {@code null}.
     */
    @Nullable
    public static Uri getReturnUri() {
        return sReturnUri;
    }

    /**
     * Clears the return uri.
     */
    public static void clearReturnUri() {
        sReturnUri = null;
    }
}

So I'm stuck on how do I get the context from this Activity?

Update I've changed my python code perform the DropInRequest.getIntent() method outside of java inside my python code with this code.

from jnius import autoclass
from jnius import cast
from android import activity
from kivy.context import get_current_context

context = autoclass('android.content.Context')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
PythonActivity = autoclass('org.kivy.android.PythonActivity')

DropInRequest = autoclass('com.braintreepayments.api.dropin.DropInRequest')
BrowserSwitchActivity = autoclass('com.braintreepayments.api.BraintreeBrowserSwitchActivity')

#Global instance
instance = None
REQUEST = 1
RESULT_OK = 1

def onBraintreeSubmit(token):
    global instance

    def on_activity_result(request, response, data):
        global instance
        if request == REQUEST:
            print response
            if response == RESULT_OK:
                result = instance.getParcelableExtra(instance.EXTRA_DROP_IN_RESULT)
                nonce = result.getPaymentMethodNonce()
                print nonce
                return nonce

    currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
    context = cast('android.content.Context', currentActivity.getApplicationContext())
    activity.bind(on_activity_result=on_activity_result)
    instance = DropInRequest()
    instance.clientToken(token)
    mapintent = Intent()
    mapintent.setClassName(context,'com.braintreepayments.api.dropin.DropInRequest')
    mapintent.putExtra("com.braintreepayments.api.EXTRA_CHECKOUT_REQUEST","EXTRA_CHECKOUT_REQUEST")

    currentActivity.startActivityForResult(mapintent,REQUEST)

and added this to my manifest

<activity android:name="com.braintreepayments.api.dropin.DropInRequest" >
    </activity>

I seem to be making progress and when I run the App I get this Error.

java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{org.test.myapp/com.braintreepayments.api.dropin.DropInRequest}: java.lang.ClassCastException: com.braintreepayments.api.dropin.DropInRequest cannot be cast to android.app.Activity

I've traced it back and DropInRequest extends Parcelable not activity...

like image 257
GoBig06 Avatar asked Apr 03 '18 23:04

GoBig06


1 Answers

To create a context with pyjnius you want to cast it like this.

PythonActivity = autoclass('org.kivy.android.PythonActivity')
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
context = cast('android.content.Context', currentActivity.getApplicationContext())
like image 74
GoBig06 Avatar answered Oct 31 '22 08:10

GoBig06