Repository navigation
fix(shareable): fund cash links copied from the Sharesheet - #1521
Merged
Merged
Conversation
Tapping the Sharesheet's own Copy button produced no confirmation modal and left the gift card unfunded, so the link the user pasted could not be collected. Picking a copy-to-clipboard app target works, which is why this looked unreproducible: the two are different controls in the same sheet. They also report differently. An app selection reaches ShareBroadcastReceiver with EXTRA_CHOSEN_COMPONENT; the Copy button reaches it with EXTRA_CHOOSER_RESULT and no component on API 35+, and goes unreported below that. The receiver read only the component, which left ShareResult.CopiedToClipboard unreachable. Parse the chooser result for CHOOSER_RESULT_COPY. The clipboard check meant to cover older releases could not run either: checkForShare() sat behind the foregroundRefreshed gate, which resets on ON_STOP, and the Sharesheet is translucent, so it pauses the activity without ever stopping it. Move the check ahead of that gate and have it wait for a clipboard the window has focus to read, since Android denies an unfocused read by reporting no clip at all and that is indistinguishable from an empty one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tapping the Sharesheet's own Copy button on a cash link produced no "Did you send the link?" modal, and the gift card was never funded, so the link the user pasted could not be collected.
initiateGiftCardFundingonly runs fromonShared(ActionTaken), so a share the app does not notice is a link that does not work.It is awkward to reproduce on purpose, because the sheet offers two different controls that both say Copy. A copy-to-clipboard app target, such as Drive's
SendTextToClipboardActivity, is a real component and has always worked. The Sharesheet's own Copy chip in the preview header is not a component at all.Why the receiver missed it
The same PendingIntent comes back two ways:
ShareBroadcastReceiverread onlyEXTRA_CHOSEN_COMPONENTand did nothing when it was absent, which leftShareResult.CopiedToClipboardunreachable. Nothing in the codebase could produce it.Why the clipboard fallback did not cover it
checkForShare()was meant to catch exactly this, and could not, for two independent reasons:foregroundRefreshed.compareAndSetinonAppInForeground, which runs on ON_RESUME, butonAppInBackgroundresets that flag from ON_STOP. The Sharesheet is translucent and pauses the activity without ever stopping it, so the pass was still spent and the call returned early.Denying clipboard access to com.flipcash.app.android, application is not in focus. A denied read reports no clip at all, which is indistinguishable from an empty clipboard.The change
ShareBroadcastReceiverparsesEXTRA_CHOOSER_RESULTwhen no component is attached and relaysCHOOSER_RESULT_COPYas a newEXTRA_COPIED_TO_CLIPBOARD. That extra is API 35+, so the parse is guarded for minSdk 29.InternalShareSheetControllerconsumes it asCopiedToClipboard.awaitClipboard()polls every 50ms up to a 1s grace period so the read lands once focus arrives, which is the only route on API 29 to 34, where the Sharesheet reports the copy not at all.checkForShare()moves above theforegroundRefreshedgate inRealSessionController, staying below the auth gate. Deduping the expensive refresh pass is unchanged and covered by a test.report()cancels any poll still in flight, so a share the Sharesheet reports mid-wait is not answered twice. A blank entropy no longer matches, since it is contained in every string and would fund a link the user never shared.15 tests cover both receiver routes, the clipboard wait and its grace expiry, double-report protection, and the lifecycle gate.