darken 33a972001e feat(upgrade): Carry pending Google Play purchases through the billing stack
Play reports a purchase as PENDING while a slow payment method (cash,
carrier billing, bank transfer) is still being processed. Until now
BillingConnection dropped those at ingestion, so the app had no idea the
user had bought anything: the upgrade screen kept selling, and a second
purchase attempt was rejected by Play with ITEM_ALREADY_OWNED.

Pending purchases now enter the reducer state and travel to the UI, while
every entitlement exit stays PURCHASED-only:

- BillingConnection ingests PURCHASED + PENDING (UNSPECIFIED_STATE is
  still dropped everywhere). The freshUpdates stream keeps receiving only
  PURCHASED, and provesAbsence now ignores a surviving PENDING overlay
  entry, so a payment in progress can't freeze the unconfirmed-episode
  clock.
- combinePurchaseResults gets the sku-type resolver: a PENDING result only
  suppresses the couldn't-verify error when it maps to a known Pro SKU. An
  unknown pending product proves nothing about the type whose query failed.
- PurchaseRefresh now carries provenance (confirmed set,
  hasConfirmedProPurchase, commit-time occurredAt, partialError) instead of
  just the merged view plus isComplete.
- BillingData splits into purchases (entitlement carrier) and
  pendingPurchases via a single from() classifier used at every exit.
- BillingManager gains processReconciliation(), run after the connect
  loop's initial refresh and by refresh(): it re-signals dead-binder
  invalidation and feeds the grace episode clock with the refresh's COMMIT
  time. The ack pass skips pending purchases, which Play rejects
  permanently and would report as a bug every pass.
- BillingConnection.querySubscriptions / BillingManager.querySubscriptions
  are replaced by refreshStrict(): the pre-purchase gate needs both product
  types and the pending state, and still fails closed on anything short of
  a complete round-trip.
- UpgradeRepoGplay exposes Info.pendingSkus (never part of isPro),
  Info.hasAutoRenewingSubscription, verifyPurchaseStateNow() for the gates,
  and reports PendingPurchaseBillingException when an already-owned
  recovery finds a pending payment. The grace branch now carries
  billingData through so pending stays visible while Pro runs on grace.
2026-08-16 17:44:02 +02:00
2025-03-19 22:29:09 +01:00
2025-03-19 22:30:14 +01:00
2021-12-28 17:11:50 +01:00
2021-12-28 17:11:50 +01:00
2021-12-28 17:12:27 +01:00
2025-03-21 19:36:03 +01:00
2026-08-07 18:28:44 +00:00
2026-08-07 18:28:44 +00:00

CAPod banner

Companion App for AirPods (CAPod)

GitHub release (latest SemVer including pre-releases) RB Status Code tests & eval Crowdin Github Downloads Google Play Downloads

A companion app that adds support for AirPod specific features to Android:

  • Battery level for pods & cases.
  • Charging status for pods & case.
  • Additional infos about connection, microphone & case.
  • Can receive and show all nearby devices.
  • Ear detection with automatic play/pause.
  • Automatically connect phone & AirPods.
  • Show popup when case is opened.
  • Widgets

CAPod is ad-free. Some additional features require an in-app purchase.

Currently supported models:

  • AirPods 1. Generation
  • AirPods 2. Generation
  • AirPods 3. Generation
  • AirPods 4. Generation
  • AirPods 4. Generation with ANC
  • AirPods Pro 1. Generation
  • AirPods Pro 2. Generation
  • AirPods Pro 2. Generation (USB-C)
  • AirPods Pro 3. Generation
  • AirPods Max
  • AirPods Max (USB-C)
  • AirPods Max 2. Generation
  • Power Beats Pro
  • Power Beats Pro 2
  • Power Beats 3
  • Power Beats 4
  • Beats Solo 3
  • Beats Solo Pro
  • Beats Solo 4
  • Beats Solo Buds
  • Beats Studio 3
  • Beats Studio Buds
  • Beats Studio Buds+
  • Beats Studio Pro
  • Beats X
  • Beats Flex
  • Beats Fit Pro
  • Fake AirPods 1. Generation 🎭
  • Fake AirPods 2. Generation 🎭
  • Fake AirPods 3. Generation 🎭
  • Fake AirPods Pro1 🎭
  • Fake AirPods Pro2 🎭

Download

Source Status
Google Play https://play.google.com/store/apps/details?id=eu.darken.capod
Google Play Beta https://play.google.com/apps/testing/eu.darken.capod
Github (Release) https://github.com/d4rken-org/capod/releases
Github (Pre-Release) https://github.com/d4rken-org/capod/releases
F-Droid https://f-droid.org/en/packages/eu.darken.capod/
F-Droid (IzzyOnDroid) https://apt.izzysoft.de/packages/eu.darken.capod/

Support the project

Get help

Screenshots

Thanks to

  • The OpenPods project, specifically @adolfintel and @Electric1447
  • Martin, Jeremy & Alpuche, Douglas & Bodeman, Kristina & Brown, Lamont & Fenske, Ellis & Foppe, Lucas & Mayberry, Travis & Rye, Erik & Sipes, Brandon & Teplov, Sam. (2019). Handoff All Your Privacy A Review of Apples Bluetooth Low Energy Continuity Protocol. Proceedings on Privacy Enhancing Technologies. 2019. 34-53. 10.2478/popets-2019-0057.
  • Celosia, Guillaume. (2020). Privacy Challenges in Wireless Communications of the Internet of Things.
  • The MagicPods project. If you are looking for "CAPod for Windows", check it out.
  • @kavishdevar and his LibrePods project for sharing a lot of cool stuff.
  • Crowdin for supporting open-source projects.

License

CAPod's code is available under a GPL v3 license, this excludes:

  • CAPod icons, logos, mascots and marketing materials/assets.
  • CAPod animations and videos.
  • CAPod documentation.
  • Google Play screenshots.
  • Google Play texts & descriptions.
  • Translations.
Languages
Kotlin 99.1%
Shell 0.8%