braintree / braintree_android

Braintree SDK for Android
https://developer.paypal.com/braintree/docs/start/hello-client/android/v4
MIT License
405 stars 232 forks source link

UserCanceledException is not thrown when the user exits Chrometab web-flow #766

Open asos-edgeorge opened 1 year ago

asos-edgeorge commented 1 year ago

Braintree SDK Version

4.36.0

Environment

Both

Android Version & Device

Google Pixel 3a XL - Android 13

Braintree dependencies

Describe the bug

When launching a ChromeTab via a method that initiated the browser switch flow (e.g. LocalPaymentClient#approveLocalPayment(FragmentActivity, LocalPaymentResult)), cancelling the browser flow via the device's back button or ChromeTab's 'X' close button does not provide a callback to the app with the expected UserCanceledException on a provided LocalPaymentListener

We believe that in v3 of the SDKs we were able to get a cancellation callback when the user quit at this stage previously

To reproduce

As described, create a basic payment flow in which a listener (e.g. LocalPaymentListener) is set and the onLocalPaymentFailure method logs when a UserCanceledException is returned

When calling a method that initiated the browser switch flow (e.g. LocalPaymentClient#approveLocalPayment(FragmentActivity, LocalPaymentResult)), manually cancel the browser flow via the device's back button or ChromeTab's 'X' close button

Observe no callback is made to the LocalPaymentListener

Expected behavior

When the user dismisses the browser before the e2e flow is complete, we would expect listeners (e.g. LocalPaymentListener) to receive a UserCanceledException via relevant failure methods such as onLocalPaymentFailure

Screenshots

No response

sshropshire commented 1 year ago

Hi @asos-edgeorge thanks for using the Braintree SDK for Android. A UserCanceledException should be delivered when the merchant app enters the foreground without completing the Local Payment flow.

If possible, can you set a breakpoint here in LocalPaymentClient.java to see if the listener code is being triggered when you execute the steps to reproduce?

asos-edgeorge commented 1 year ago

@sshropshire Thanks for your quick response

I am seeing some IDE issues in that the sources do not match the bytecode when setting breakpoints in the LocalPaymentClient code, but I am 99.9% sure I am not seeing the listener code at the line you provided being triggered.

sshropshire commented 1 year ago

Ok what about here in LocalPaymentLifecycleObserver.java? Also can you share how you're instantiating LocalPaymentClient in your host Fragment / Activity, and in which lifecycle method you do so (e.g. onCreate())?

asos-edgeorge commented 1 year ago

We aren't using a singleton LocalPaymentClient, but instead construct it when it's needed - so it isn't in a lifecycle method

private inline fun withLocalPaymentClient(token: String, block: LocalPaymentClient.(FragmentActivity) -> Any) {
        val fragment = getPaymentFragment()
        val activity = fragment.requireActivity()
        LocalPaymentClient(fragment, fragment.generateBraintreeClient(token)).run {
            block(activity)
        }
    }

We do see the lifecycle methods reporting correctly for LocalPaymentLifecycleObserver and the break point is hit for each lifecycle method

sshropshire commented 1 year ago

Got it. From my perspective your integration sounds standard. The listener must also be set on LocalPaymentClient in order to receive the result from a browser switch. I would step through in LocalPaymentLifecycleObserver to see if LocalPaymentClient#onBrowserSwitchResult() is called, and to make sure the client notifies its listener via onLocalPaymentSuccess().

asos-edgeorge commented 1 year ago

Just to update here - I don't believe the callbacks are called, which I suspect is a bug. Would it be possible to be notified when the user exits the ChromeTab in the browser switch flow in a future release?

sshropshire commented 1 year ago

@asos-edgeorge unfortunately there isn't a way to get a notification for a close event through the Chrome Custom Tabs API that I'm aware of. Is it possible for your app to instantiate the LocalPaymentClient in onCreate() like we mention in our migration guide?

tdchow commented 1 month ago

Hey @asos-edgeorge! We just released a beta for the next major version, v5.

In this version, the interface has been updated to give the additional browser switch flexibility. We'd love for you to try out the new version and see if the new integration pattern resolves the original browser switch cancel issue.

v5 Local Payment Migration Guide: https://github.com/braintree/braintree_android/blob/main/v5_MIGRATION_GUIDE.md#local-payment v5 Release: https://github.com/braintree/braintree_android/releases/tag/5.0.0-beta1