diff --git a/.ghost-portfolio.yml b/.ghost-portfolio.yml index 9536c50..19959a6 100644 --- a/.ghost-portfolio.yml +++ b/.ghost-portfolio.yml @@ -1,7 +1,7 @@ description: "Android companion app for CashPilot — monitors passive income apps running on your phone without root." personalNote: "CashPilot manages Docker containers on servers, but some passive income apps only run on Android. This agent detects which apps are installed and active using three complementary APIs — no root needed — and reports back to the fleet dashboard." keyFeatures: - - "Detects 11 passive income apps via NotificationListener, NetworkStats, and UsageStats" + - "Detects 10 passive income apps via NotificationListener, NetworkStats, and UsageStats" - "Periodic heartbeats to CashPilot server for unified fleet monitoring" - "No root required — uses standard Android APIs (API 26+)" techStack: "Kotlin, Jetpack Compose, Ktor, Material 3, WorkManager" diff --git a/CHANGELOG.md b/CHANGELOG.md index 1de3735..0f1a0b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Removed + +- **Uprock is no longer watched on Android.** Google Play Protect removes Uprock's own app from phones, so a Play-listed CashPilot that sends people to install it would put the app's Play review at risk. The app now watches 10 apps. CashPilot web and Desktop keep Uprock. + ### Changed - **Heartbeats run every 15 minutes on WorkManager instead of every 30 seconds from a foreground service.** The always-on special-use foreground service and its permanent notification are gone, and so is the restart-on-boot receiver: WorkManager keeps the schedule across restarts. The app also reports once when it is opened and once when the server URL or key changes. The last report and the last earnings figure are kept on disk, so the dashboard still shows them after Android stops the app between runs, and it now says "Last report 6 min ago · sent every 15 min" instead of implying live monitoring. diff --git a/CLAUDE.md b/CLAUDE.md index b7f236b..7080a46 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ # CLAUDE.md — CashPilot Android ## Overview -Android monitoring agent for CashPilot that tracks passive income apps (EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Uprock, Wipter) without root, reporting their status to the CashPilot fleet dashboard via periodic heartbeats. +Android monitoring agent for CashPilot that tracks passive income apps (EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Wipter) without root, reporting their status to the CashPilot fleet dashboard via periodic heartbeats. ## Tech Stack - Kotlin 2.1+ @@ -103,7 +103,7 @@ POST to `{serverUrl}/api/workers/heartbeat` with bearer auth (fleet API key via ## Known Apps -11 passive income apps with verified Android package names defined in `KnownApps.kt`. All verified via `adb shell pm list packages`. +10 passive income apps with verified Android package names defined in `KnownApps.kt`. All verified via `adb shell pm list packages`. When adding new apps: 1. **Verify exact package name** via `adb shell pm list packages | grep -i ` — Play Store URLs are unreliable diff --git a/PUBLISHING.md b/PUBLISHING.md index eef65b4..b5f4885 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -109,9 +109,9 @@ issue on its repository. - **Closed testing first.** A personal developer account created after 2023-11-13 must run a closed test with at least 12 testers for 14 days before production. Confirm the current numbers in Play Console. -- **3 of the 11 monitored apps are not on Play** (Traffmonetizer, ByteBenefit, - Uprock return 404 for their package ids). Linking to apps outside Play from a - Play listing invites questions. +- **2 of the 10 monitored apps are not on Play** (Traffmonetizer and ByteBenefit + return 404 for their package ids). Linking to apps outside Play from a Play + listing invites questions. - **Android developer verification.** Google started requiring verified developer identities for sideloaded apps on 2026-09-30 in Brazil, Indonesia, Singapore and Thailand, and plans it globally in 2027. That affects F-Droid, diff --git a/README.md b/README.md index a4e61b3..9698e47 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ CashPilot Android is the Android companion app for [CashPilot](https://github.co ## Features -- Detects 11 passive income apps: EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Uprock, Wipter +- Detects 10 passive income apps: EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Wipter - Instant detection from each app's ongoing notification (NotificationListenerService) - Confirms activity from per-app network traffic and recent foreground use (NetworkStatsManager, UsageStatsManager) - Periodic heartbeats to your server (`POST /api/workers/heartbeat`), so phones appear next to Docker workers in the fleet view diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 06fad4e..b468235 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,7 +18,6 @@ - diff --git a/app/src/main/java/com/cashpilot/android/model/MonitoredApp.kt b/app/src/main/java/com/cashpilot/android/model/MonitoredApp.kt index 2a92e2a..03e4736 100644 --- a/app/src/main/java/com/cashpilot/android/model/MonitoredApp.kt +++ b/app/src/main/java/com/cashpilot/android/model/MonitoredApp.kt @@ -35,8 +35,6 @@ object KnownApps { MonitoredApp("titan", "com.titan_network_vip.titan_app", "Titan Network", referralUrl = "https://edge.titannet.info/signup?inviteCode=2GKKJ495"), MonitoredApp("nodle", "io.nodle.cash", "Nodle Cash"), - MonitoredApp("uprock", "com.uprock.mining", "Uprock", - referralUrl = "https://link.uprock.com/i/33e8492e"), MonitoredApp("wipter", "com.wipter.app", "Wipter"), ) diff --git a/app/src/test/java/com/cashpilot/android/AppPresentationTest.kt b/app/src/test/java/com/cashpilot/android/AppPresentationTest.kt index 409eddf..680edc0 100644 --- a/app/src/test/java/com/cashpilot/android/AppPresentationTest.kt +++ b/app/src/test/java/com/cashpilot/android/AppPresentationTest.kt @@ -149,7 +149,7 @@ class AppPresentationTest { // grid reshuffles under the user's thumb on every 30-second refresh. val once = AppPresentation.sortForDashboard( listOf( - info(AppState.STOPPED, "uprock", "Uprock"), + info(AppState.STOPPED, "wipter", "Wipter"), info(AppState.STOPPED, "earnapp", "EarnApp"), info(AppState.STOPPED, "grass", "Grass"), ), @@ -157,11 +157,11 @@ class AppPresentationTest { val again = AppPresentation.sortForDashboard( listOf( info(AppState.STOPPED, "grass", "Grass"), - info(AppState.STOPPED, "uprock", "Uprock"), + info(AppState.STOPPED, "wipter", "Wipter"), info(AppState.STOPPED, "earnapp", "EarnApp"), ), ) - assertEquals(listOf("earnapp", "grass", "uprock"), once.map { it.app.slug }) + assertEquals(listOf("earnapp", "grass", "wipter"), once.map { it.app.slug }) assertEquals(once.map { it.app.slug }, again.map { it.app.slug }) } diff --git a/app/src/test/java/com/cashpilot/android/EarningsPresentationTest.kt b/app/src/test/java/com/cashpilot/android/EarningsPresentationTest.kt index f830b7d..e635fc5 100644 --- a/app/src/test/java/com/cashpilot/android/EarningsPresentationTest.kt +++ b/app/src/test/java/com/cashpilot/android/EarningsPresentationTest.kt @@ -61,7 +61,7 @@ class EarningsPresentationTest { // Some platforms unread is normal; the total covers the ones that were. assertEquals( Mode.FIGURE, - EarningsPresentation.mode(earnings(3.0, without = listOf("titan", "uprock")), serverConfigured = true), + EarningsPresentation.mode(earnings(3.0, without = listOf("titan", "wipter")), serverConfigured = true), ) } diff --git a/docs/configuration.md b/docs/configuration.md index 88948ab..f134219 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -9,7 +9,7 @@ Everything the app stores, where you set it, and what it does. There are no conf | CashPilot Server URL | Setup step 1, or Settings, Server Connection | `server_url` | empty | Base URL of your CashPilot server. Heartbeats go to `/api/workers/heartbeat`; a trailing `/` is ignored. Empty means standalone: no heartbeats, no earnings. | | Fleet API Key | Setup step 1, or Settings, Server Connection | `api_key` | empty | The server's `CASHPILOT_API_KEY`. Used only until the phone has its own key (next section). | | Per-worker key | Nothing to set: the server issues it | `worker_key` | empty | This phone's own key, received on its first heartbeat and used for every heartbeat after that. | -| Monitored apps | Settings, Monitored Apps | `enabled_slugs` | all 11 on | Which apps the dashboard and the heartbeat include. A switched-off app shows as **Disabled** and is left out of the heartbeat. | +| Monitored apps | Settings, Monitored Apps | `enabled_slugs` | all 10 on | Which apps the dashboard and the heartbeat include. A switched-off app shows as **Disabled** and is left out of the heartbeat. | | Heartbeat interval | No control in the app | `heartbeat_interval` | 30 seconds | Stored but no longer used. Heartbeats run every 15 minutes, the shortest period Android's WorkManager allows. | | Setup completed | Finishing or skipping the setup screen | `setup_completed` | false | Whether the setup screen is shown at launch. An install that already had a URL and a key before this setting existed counts as set up. | @@ -48,7 +48,7 @@ The server side of this is on CashPilot's [fleet page](https://geiserx.github.io ## Monitored apps -The app knows these 11 apps. The slug is the name the CashPilot server uses for the service; the package name is what the phone looks for. +The app knows these 10 apps. The slug is the name the CashPilot server uses for the service; the package name is what the phone looks for. | App | Slug | Package | |---|---|---| @@ -61,7 +61,6 @@ The app knows these 11 apps. The slug is the name the CashPilot server uses for | Grass | `grass` | `io.getgrass.www` | | Titan Network | `titan` | `com.titan_network_vip.titan_app` | | Nodle Cash | `nodle` | `io.nodle.cash` | -| Uprock | `uprock` | `com.uprock.mining` | | Wipter | `wipter` | `com.wipter.app` | Adding an app takes a new release: the list is in the code, and Android 11 and later only let the app see packages declared in its manifest. diff --git a/docs/getting-started.md b/docs/getting-started.md index ccec76e..dcde48a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -29,7 +29,7 @@ The main button unlocks once both accesses are granted. It reads **Continue to D ## What a working start looks like -- The dashboard lists the 11 monitored apps. Installed ones show **Running**, **Stopped** or **Can't tell**; the others show **Not installed — tap to install**. The summary at the top counts them. +- The dashboard lists the 10 monitored apps. Installed ones show **Running**, **Stopped** or **Can't tell**; the others show **Not installed — tap to install**. The summary at the top counts them. - With a server, the dashboard's summary shows a green dot and **Last report** with its age, for example **Last report 6 min ago · sent every 15 min**, and the phone appears on the server's fleet page as its maker and model plus a short device id, for example `Google Pixel 8 (a1b2c3d4)`. The first heartbeat also enrolls the phone: the server issues it its own key ([Configuration](configuration.md#the-fleet-key-and-enrollment)). - Without a server, the summary shows **Not paired — running standalone**. That is a supported mode, not an error. diff --git a/docs/index.md b/docs/index.md index abaa8d7..86267fe 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,7 +18,7 @@ hide: --- -**CashPilot Android** tells you which of your passive income apps are actually running on your phone, without root. It watches 11 apps (EarnApp, IPRoyal Pawns, MystNodes, Grass and more) through three Android APIs. A bandwidth app that has stopped earns nothing and usually shows nothing on the phone; here it goes to the top of the list in red. Paired with a [CashPilot](https://geiserx.github.io/CashPilot/) server, the phone joins your fleet next to the Docker workers and shows what its platforms earned. Start with [Getting started](getting-started.md), then [Usage](usage.md). +**CashPilot Android** tells you which of your passive income apps are actually running on your phone, without root. It watches 10 apps (EarnApp, IPRoyal Pawns, MystNodes, Grass and more) through three Android APIs. A bandwidth app that has stopped earns nothing and usually shows nothing on the phone; here it goes to the top of the list in red. Paired with a [CashPilot](https://geiserx.github.io/CashPilot/) server, the phone joins your fleet next to the Docker workers and shows what its platforms earned. Start with [Getting started](getting-started.md), then [Usage](usage.md).
@@ -71,7 +71,7 @@ hide: - It does not start, stop or control the apps. It watches them; restarting a stopped one is up to you. - It does not read notification content, only whether a monitored app has an ongoing notification. - It does not collect earnings itself. The figures come from the CashPilot server, and without one the earnings card stays empty. -- It watches the 11 apps it knows. A new app needs a new release. +- It watches the 10 apps it knows. A new app needs a new release. ## Privacy diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index b727e29..57ea5a6 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -1,6 +1,6 @@ CashPilot shows which of your passive-income and DePIN apps are installed, running and active on this phone. It needs no root. -It watches EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Uprock and Wipter. For each one it shows whether the app is installed, whether it is running, and when it was last active. +It watches EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash and Wipter. For each one it shows whether the app is installed, whether it is running, and when it was last active. How it knows: - Notification access: most of these apps keep a notification up while they run, so CashPilot reads it to tell that the app is alive.