feature(PayPal): collect and send device_info to determine app switch eligibility - #1600
Conversation
0025eb8 to
f30f4ca
Compare
|
@santugowda please follow the |
- Wrap ActivityManager.getMemoryInfo() in withContext(Dispatchers.IO) to avoid Binder IPC on Dispatchers.Main - Switch getJSONObject → optJSONObject in injectDeviceInfo for defense-in-depth (outer guard already ensures the key exists, but this makes the function safe in isolation) - Extract hardcoded "ANDROID" string to OS_TYPE_VALUE constant in PayPalRequest - Rename MODEL_KEY → DEVICE_MODEL_KEY for consistency with sibling constants - Promote activityManager to class field in unit tests with non-zero default memory values in beforeEach, removing per-test mock duplication - Add instrumentation test for PayPalVaultRequest app switch nested structure - Add unit test for vault path device_info injection - Add unit test for no-op when app switch enabled but no app link present Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
/inner source |
|
@anbojorquez @ayer-ribeiro could you please review this PR? Thanks! |
|
/ready |
|
In testing the PayPal checkout flows I noticed that single payment with app switch works as expected with the new fields. However, when I enable PP app switch and try to checkout with vault I get an error |
@saralvasquez This was existing issue in BT Demo App(I see this issue on Main branch as well). |
|
I get different behavior on the main branch vs this branch. On the main branch when the vault option is selected app switch happens and then inside the PP app the payment can't complete. On this branch when the vault option is selected there is no app switch at all and we simply get the error inside the demo app |
Ok, I do see the error now on this branch alone. (had to use a physical device) Below is the error response I get - I don't see any token or correlationID to investigate on this error on BE side - any pointers on this. |
@saralvasquez Found the issue - it was missing fields in the request body. Will push this fix in a bit. |
Fixed this in the lastest commit i.e. #1600 434accf BillingFlow_BTDemoApp.mp4 |
|
I noticed the same behavior when re-testing just now |
|
ok, should be a error on BE. It's the same experience on |
|
Single Payment is working now. SinglePaymentInProd.mp4Slack thread has the info about yesterday's error, yet to close out on the root cause. |
| .build() | ||
| } | ||
|
|
||
| private fun injectDeviceInfo(context: Context, requestBody: String): String { |
There was a problem hiding this comment.
nit: will defer to android folks but append may be a better name vs inject
There was a problem hiding this comment.
Yeah I agree here. Append is preferable
|
@santugowda instrumentation tests are failing here but passing on other branches. Is this something you want to take a look at? |
saralvasquez
left a comment
There was a problem hiding this comment.
I've tested both checkout and vault and both work as expected. I just have a couple nits about comments and I'd like to see the change Jax mentioned about inject vs append. I'll approve once we have a clean build besides the known security check failure
…edundant test comments Address review feedback on PR braintree#1600: - Rename injectDeviceInfo -> appendDeviceInfo per reviewer preference - Remove unnecessary explanatory comments in PayPal request unit tests Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Pushed the changes addressing all the above nit comments, |
saralvasquez
left a comment
There was a problem hiding this comment.
Once we get a clean build I'd say this is ready to go in
|
CI is 🟢 except for the known Dependency Review failure. |
|
@santugowda can you please update with the latest from main and move the changelog entry under a new unreleased section? |
… eligibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Wrap ActivityManager.getMemoryInfo() in withContext(Dispatchers.IO) to avoid Binder IPC on Dispatchers.Main - Switch getJSONObject → optJSONObject in injectDeviceInfo for defense-in-depth (outer guard already ensures the key exists, but this makes the function safe in isolation) - Extract hardcoded "ANDROID" string to OS_TYPE_VALUE constant in PayPalRequest - Rename MODEL_KEY → DEVICE_MODEL_KEY for consistency with sibling constants - Promote activityManager to class field in unit tests with non-zero default memory values in beforeEach, removing per-test mock duplication - Add instrumentation test for PayPalVaultRequest app switch nested structure - Add unit test for vault path device_info injection - Add unit test for no-op when app switch enabled but no app link present Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eInfo ActivityManager.getMemoryInfo(), Build.MODEL, and JSON operations are not I/O-bound; no dispatcher switch is needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The gateway still requires the top-level os_version, os_type, and merchant_app_return_url fields for PayPal app switch. Sending only the nested app_switch_context caused a 503 "PayPal is currently unable to handle the request". Restore the flat fields while keeping the nested app_switch_context (native_app + device_info). Update PayPalCheckoutRequest/PayPalVaultRequest unit tests to assert both the flat and nested app switch parameters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use a safe cast for the ACTIVITY_SERVICE lookup and return the original request body if the service is unavailable, so device_info injection never crashes a merchant's checkout on the request path. Add a unit test covering the null-service fallback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the nested native_app block (os_type/os_version/app_url) from the PayPal app-switch request. Those values duplicate the flat top-level fields (os_type/os_version/merchant_app_return_url) that BTGW reads, so the nested copy was redundant. app_switch_context now carries only device_info. injectDeviceInfo now creates app_switch_context when absent, since the request no longer builds it. Updated unit tests to expect the new shape. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…edundant test comments Address review feedback on PR braintree#1600: - Rename injectDeviceInfo -> appendDeviceInfo per reviewer preference - Remove unnecessary explanatory comments in PayPal request unit tests Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…text.native_app createRequestBody no longer emits the nested app_switch_context.native_app structure, so the instrumentation tests now assert the flat app switch fields (os_type, os_version, merchant_app_return_url) and that app_switch_context is absent. Fixes the failing PayPal instrumentation tests on this branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1f34dd6 to
0d1d28a
Compare
@jaxdesmarais - rebased and updated Changelog.md. Hoping to get this merged today. |
Summary of changes
Collects and sends device information as
app_switch_context.device_infoin PayPal Hermes requests whenenablePayPalAppSwitchis enabled. This data allows the PayPal server to determine app switch eligibility, primarily for low-RAM devices.Background
The PayPal App Switch flow launches the PayPal native app directly, bypassing browser checkout. On low-RAM devices, running two apps simultaneously (the merchant app + PayPal app) can cause the OS to kill the merchant app in the background due to memory pressure — leading to a broken checkout experience when the user tries to return.
The PayPal server uses
memory_available_mbandmemory_total_mbto gate app switch eligibility — if the device doesn't have enough RAM, the server skips app switch and falls back to browser checkout (Chrome Custom Tab), which is lighter on memory.This PR adds collection and injection of:
model— device model (e.g.SM-A166U) for any device-specific overrides the server may havememory_available_mb— free RAM at request timememory_total_mb— total device RAMThese are injected into the request body under
app_switch_context.device_info, giving the server everything it needs to decide whether to serve an app switch URL or a browser URL in the response.JSON structure sent to BTGW
{ "launch_paypal_app": true, "os_type": "Android", "os_version": "36", "merchant_app_return_url": "https://...", "app_switch_context": { "device_info": { "model": "SM-A166U", "memory_available_mb": 350, "memory_total_mb": 4096 } } }Changes:
PayPalRequest: removed the now-unusedNATIVE_APP_KEY,APP_URL_KEY, andOS_TYPE_VALUEconstantsPayPalCheckoutRequest/PayPalVaultRequest: removed the nestedapp_switch_context.native_appblock (redundant with the retained flatos_type/os_version/merchant_app_return_urlkeys)PayPalInternalClient:injectDeviceInfo()addsdevice_info(model, memory_available_mb, memory_total_mb) intoapp_switch_context, creating the object when absentSteps to Test
enablePayPalAppSwitch = trueonPayPalCheckoutRequestorPayPalVaultRequestpaypal_hermes/create_payment_resourceorpaypal_hermes/setup_billing_agreementapp_switch_context.device_infois present in the request body withmodel,memory_available_mb, andmemory_total_mbAI Usage
Which AI Agent Was Used?
How was AI used?
Code generation, cross-codebase analysis (Android SDK, BTGW, backend), refactoring the request structure, on-device request/response verification, and writing tests.
Estimated AI Code Contribution
Checklist
Authors
Inner Source Process
Internal to PayPal contributors should fill out this section. All others can delete.
PR should follow these steps before codeowners review will begin:
/inner sourceon this PR — this will automatically add theinner sourceandtech lead review requiredlabels. Open the PR in a draft state./readyon this PR — this will automatically remove thetech lead review requiredlabel. Move the PR to ready to review.Demo
Request body sent (key fields):
{ "launch_paypal_app": true, "os_type": "Android", "os_version": "36", "merchant_app_return_url": "https://mobile-sdk-demo-site-838cead5d3ab.herokuapp.com/braintree-payments", "app_switch_context": { "device_info": { "model": "SM-S936U", "memory_available_mb": 350, "memory_total_mb": 11113 } } }token=232345522J779231L
EC flow
paypal_appswitch_test.mp4
Billing Successful app-switch
BillingWithSupportedDevice.mp4
Billing on Low Ram device not app-switching
BillingWithLowRamDevice.mp4
Inner Source Checklist