feature(PayPal): collect and send device_info to determine app switch eligibility#1600
feature(PayPal): collect and send device_info to determine app switch eligibility#1600santugowda wants to merge 16 commits into
Conversation
… eligibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
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! |
…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>
|
/ready |
Signed-off-by: Sara Vasquez <98496950+saralvasquez@users.noreply.github.com>
|
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 |
There was a problem hiding this comment.
Pull request overview
This PR enhances PayPal Hermes request payloads when PayPal app switch is enabled by adding device memory/model data under app_switch_context.device_info, enabling the server to determine app-switch eligibility on low-RAM devices. It also introduces a nested app_switch_context.native_app structure and updates tests/changelog accordingly.
Changes:
- Inject
device_info(model, available/total memory MB) into PayPal Hermes request bodies when app switch is enabled and an app link is available. - Add nested
app_switch_context.native_apprequest structure and update request constants. - Update unit/instrumentation tests and add a changelog entry.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalInternalClient.kt | Injects device memory/model into request JSON under app_switch_context.device_info. |
| PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalCheckoutRequest.kt | Adds app_switch_context.native_app structure to checkout request body when app switch is enabled. |
| PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalVaultRequest.kt | Adds app_switch_context.native_app structure to vault request body when app switch is enabled. |
| PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalRequest.kt | Adds constants for new nested keys and device info fields. |
| PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalInternalClientUnitTest.kt | Adds coverage asserting device_info injection and absence when app switch/context isn’t applicable. |
| PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalCheckoutRequestUnitTest.kt | Updates request-body assertions to validate nested app_switch_context.native_app structure. |
| PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalVaultRequestUnitTest.kt | Updates request-body assertions to validate nested app_switch_context.native_app structure. |
| PayPal/src/androidTest/java/com/braintreepayments/api/paypal/PayPalCheckoutRequestTest.kt | Updates instrumentation tests to validate nested app-switch JSON structure. |
| PayPal/src/androidTest/java/com/braintreepayments/api/paypal/PayPalVaultRequestTest.kt | Adds instrumentation coverage for nested native_app structure when app switch is enabled. |
| CHANGELOG.md | Adds an entry describing the new device info fields sent for PayPal app switch eligibility. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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>
|
As a follow up, i tested the flows and inspected request that are sent to |
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
saralvasquez
left a comment
There was a problem hiding this comment.
A couple open questions but the logic makes sense to me
|
Hey there again, I tested the flows one more time, and the Checkout flow does not app switch anymore. The vault completes with no problems though. Please note we will want both flows working exactly as expected before merging. Attaching the video: Screen.Recording.2026-07-09.at.2.43.41.PM.mov |
|
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. |
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>
| .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>
…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>
|
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. |
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