From 300c5fa5a85c9c3499d3f3f48565b0d7278e3299 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 13 Aug 2026 02:03:33 +0000 Subject: [PATCH 1/2] fix(notify): open MainActivity when notification is tapped Without a setContentIntent, tapping an activity-time alert notification did nothing. Add a PendingIntent that brings MainActivity to the front (or starts it), opening the AW dashboard/activity view. BackgroundService already had this pattern for the foreground-service notification; NotifyWorker's category-alert notifications were missing it. Fixes: ActivityWatch/aw-android#224 --- .../activitywatch/android/workers/NotifyWorker.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt b/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt index ccbcb5bd..c4099097 100644 --- a/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt +++ b/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt @@ -2,13 +2,16 @@ package net.activitywatch.android.workers import android.app.NotificationChannel import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context +import android.content.Intent import android.os.Build import android.util.Log import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters import com.jakewharton.threetenabp.AndroidThreeTen +import net.activitywatch.android.MainActivity import net.activitywatch.android.R import net.activitywatch.android.RustInterface import org.json.JSONArray @@ -179,12 +182,24 @@ class NotifyWorker(context: Context, params: WorkerParameters) : Worker(context, val body = "${alert.label}: $thresholdStr" + if (thresholdStr != actualStr) " ($actualStr)" else "" + // Open the activity/timeline view in MainActivity when the notification is tapped. + val openIntent = Intent(applicationContext, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + } + val pendingIntent = PendingIntent.getActivity( + applicationContext, + 0, + openIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID) .setContentTitle(if (alert.positive) "Goal reached!" else "Time spent") .setContentText(body) .setSmallIcon(R.mipmap.aw_launcher_round) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setAutoCancel(true) + .setContentIntent(pendingIntent) .build() // Stable ID per alert so notifications update in-place rather than stacking From 64c933db8fbf0f66c79f8521194d1ab0131b9ed7 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 17 Aug 2026 07:19:05 +0000 Subject: [PATCH 2/2] fix(notify): use a distinct PendingIntent request code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BackgroundService's foreground notification already registers request code 0 for a MainActivity PendingIntent with no launch flags. PendingIntent identity is (requestCode, Intent.filterEquals) — extras and launch flags are not part of it, and FLAG_UPDATE_CURRENT replaces only extras. Reusing code 0 therefore resolved to that existing PendingIntent and silently dropped FLAG_ACTIVITY_CLEAR_TOP, so tapping an alert could stack a second MainActivity instead of bringing the existing one forward. Use request code 1 (0 and 2 are taken by BackgroundService and the widget) and name the collision in a comment so it does not regress. --- .../net/activitywatch/android/workers/NotifyWorker.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt b/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt index c4099097..c24314f8 100644 --- a/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt +++ b/mobile/src/main/java/net/activitywatch/android/workers/NotifyWorker.kt @@ -26,6 +26,12 @@ private const val CHANNEL_ID = "aw_notify_channel" private const val PREFS_NAME = "aw_notify_prefs" private const val DEFAULT_START_OF_DAY_HOUR = 4 +// PendingIntent identity ignores extras and Intent launch flags, so a request code +// shared with another MainActivity PendingIntent resolves to that existing instance +// and silently drops our FLAG_ACTIVITY_CLEAR_TOP. Request codes already taken: +// 0 = BackgroundService foreground notification, 2 = CategoryTimeWidget open button. +private const val PENDING_INTENT_REQUEST_CODE = 1 + // Mirrors desktop aw-notify CategoryAlert semantics. // positive=true → "Goal reached!" title; false → "Time spent" internal data class CategoryAlert( @@ -188,7 +194,7 @@ class NotifyWorker(context: Context, params: WorkerParameters) : Worker(context, } val pendingIntent = PendingIntent.getActivity( applicationContext, - 0, + PENDING_INTENT_REQUEST_CODE, openIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, )