Skip to content

Commit a69c64b

Browse files
committed
Fix notification detection, IP privacy gate, and docs
- Only count ongoing (foreground service) notifications, not transient promos/updates. On removal, re-scan remaining notifications instead of blindly clearing the package. - Require both serverUrl AND apiKey for public IP fetch; clear IP when server config is removed. - Update README and fastlane to reflect 11 verified apps.
1 parent 3971a71 commit a69c64b

4 files changed

Lines changed: 35 additions & 16 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ It sends periodic heartbeats to your CashPilot server, so you get a unified flee
1616

1717
## Supported Apps
1818

19-
17 passive income services with Android apps:
19+
11 passive income services with Android apps:
2020

21-
Honeygain, EarnApp, IPRoyal Pawns, Mysterium, PacketStream, Traffmonetizer, Repocket, Peer2Profit, Bytelixir, ByteBenefit, Grass, GagaNode, Titan Network, Nodle Cash, PassiveApp, Uprock, Wipter
21+
EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Uprock, Wipter
2222

2323
## Setup
2424

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cashpilot.android.service
22

3+
import android.app.Notification
34
import android.service.notification.NotificationListenerService
45
import android.service.notification.StatusBarNotification
56
import com.cashpilot.android.model.KnownApps
@@ -9,48 +10,60 @@ import java.util.concurrent.atomic.AtomicBoolean
910
/**
1011
* Listens for status bar notifications from monitored passive income apps.
1112
*
12-
* When a bandwidth-sharing app is running, it shows a persistent foreground
13-
* notification. This service detects when those notifications appear/disappear,
14-
* giving us an instant signal of whether each app is actively running.
13+
* Only counts ongoing (FLAG_ONGOING_EVENT) notifications, which correspond to
14+
* foreground service notifications. Transient notifications (promos, updates)
15+
* are ignored.
16+
*
17+
* On removal, re-scans remaining notifications for the package instead of
18+
* blindly clearing — so dismissing one notification doesn't create a false
19+
* "stopped" if the foreground service notification is still present.
1520
*
1621
* Requires the user to grant Notification Access in system settings.
1722
*/
1823
class AppNotificationListener : NotificationListenerService() {
1924

2025
override fun onNotificationPosted(sbn: StatusBarNotification) {
2126
val pkg = sbn.packageName
22-
if (pkg in KnownApps.byPackage) {
27+
if (pkg in KnownApps.byPackage && sbn.isOngoing) {
2328
activeNotifications_[pkg] = System.currentTimeMillis()
2429
}
2530
}
2631

2732
override fun onNotificationRemoved(sbn: StatusBarNotification) {
28-
activeNotifications_.remove(sbn.packageName)
33+
val pkg = sbn.packageName
34+
if (pkg !in KnownApps.byPackage) return
35+
36+
// Check if any ongoing notification remains for this package
37+
val stillHasOngoing = activeNotifications?.any {
38+
it.packageName == pkg && it.isOngoing
39+
} ?: false
40+
41+
if (!stillHasOngoing) {
42+
activeNotifications_.remove(pkg)
43+
}
2944
}
3045

3146
override fun onListenerConnected() {
3247
connected.set(true)
33-
// Full resync: clear stale state, then scan current notifications
48+
// Full resync: clear stale state, then scan current ongoing notifications
3449
activeNotifications_.clear()
3550
activeNotifications?.forEach { sbn ->
3651
val pkg = sbn.packageName
37-
if (pkg in KnownApps.byPackage) {
52+
if (pkg in KnownApps.byPackage && sbn.isOngoing) {
3853
activeNotifications_[pkg] = System.currentTimeMillis()
3954
}
4055
}
4156
}
4257

4358
override fun onListenerDisconnected() {
4459
connected.set(false)
45-
// Clear all state — we can no longer trust notification presence
4660
activeNotifications_.clear()
4761
}
4862

4963
companion object {
50-
/** Package name → timestamp when notification was last seen. */
64+
/** Package name → timestamp when ongoing notification was last seen. */
5165
val activeNotifications_ = ConcurrentHashMap<String, Long>()
5266

53-
/** Whether the listener is currently connected to the system. */
5467
private val connected = AtomicBoolean(false)
5568

5669
fun isAppNotificationActive(packageName: String): Boolean {
@@ -61,3 +74,6 @@ class AppNotificationListener : NotificationListenerService() {
6174
fun isConnected(): Boolean = connected.get()
6275
}
6376
}
77+
78+
private val StatusBarNotification.isOngoing: Boolean
79+
get() = notification.flags and Notification.FLAG_ONGOING_EVENT != 0

app/src/main/java/com/cashpilot/android/ui/MainViewModel.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
134134
totalRx = result.mapNotNull { it.status?.netRx24h }.sum(),
135135
)
136136
checkPermissions()
137-
// Only fetch public IP once the server is configured (post-setup)
138-
if (_publicIp.value == null && settings.value.serverUrl.isNotBlank()) {
137+
// Only fetch public IP when fully configured (both URL + key = setup complete)
138+
val serverReady = settings.value.serverUrl.isNotBlank() && settings.value.apiKey.isNotBlank()
139+
if (serverReady && _publicIp.value == null) {
139140
fetchPublicIp()
141+
} else if (!serverReady) {
142+
_publicIp.value = null
140143
}
141144
_isRefreshing.value = false
142145
}

fastlane/metadata/android/en-US/full_description.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CashPilot Android is a monitoring agent for CashPilot, the self-hosted passive income orchestrator. It tracks earnings from bandwidth sharing, DePIN, storage, and GPU compute services running on your phone — without root access.
22

33
Features:
4-
- Monitors passive income apps (Honeygain, EarnApp, Grass, etc.) via NotificationListenerService
5-
- Reports earnings and app status to your self-hosted CashPilot server
4+
- Monitors passive income apps (EarnApp, Grass, MystNodes, etc.) via NotificationListenerService
5+
- Reports app status to your self-hosted CashPilot server
66
- Lightweight foreground service with minimal battery impact
77
- Usage statistics and network bandwidth tracking
88
- Material Design 3 UI with Jetpack Compose

0 commit comments

Comments
 (0)