Browse Source
- Add notification channel creation in TimeSafariApplication for Android 8.0+ Required for daily notifications to display properly. Channel ID matches plugin's 'timesafari.daily' channel. - Convert localhost to 10.0.2.2 in CapacitorPlatformService for Android emulators Android emulators cannot reach localhost - they need 10.0.2.2 to access the host machine's API server. - Refresh native fetcher configuration when API server changes in AccountViewView Ensures background notification prefetch uses the updated endpoint when user changes API server URL in settings. - Add directive for fixing notification dismiss cancellation in plugin Documents the fix needed in plugin source to cancel notification from NotificationManager when dismiss button is clicked. These changes ensure daily notifications work correctly on Android, including proper channel setup, emulator network connectivity, and configuration refresh.pull/214/head
4 changed files with 196 additions and 1 deletions
@ -0,0 +1,109 @@ |
|||||
|
# Fix Notification Dismiss to Cancel Notification |
||||
|
|
||||
|
## Problem |
||||
|
|
||||
|
When a user clicks the "Dismiss" button on a daily notification, the notification is removed from storage and alarms are cancelled, but the notification itself is not cancelled from the NotificationManager. This means the notification remains visible in the system tray even though it's been dismissed. |
||||
|
|
||||
|
Additionally, clicking on the notification (not the dismiss button) launches the app, which is working as intended. |
||||
|
|
||||
|
## Root Cause |
||||
|
|
||||
|
In `DailyNotificationWorker.java`, the `handleDismissNotification()` method: |
||||
|
1. ✅ Removes notification from storage |
||||
|
2. ✅ Cancels pending alarms |
||||
|
3. ❌ **MISSING**: Does not cancel the notification from NotificationManager |
||||
|
|
||||
|
The notification is displayed with ID = `content.getId().hashCode()` (line 440), but this ID is never used to cancel the notification when dismissing. |
||||
|
|
||||
|
## Solution |
||||
|
|
||||
|
Add notification cancellation to `handleDismissNotification()` method in `DailyNotificationWorker.java`. |
||||
|
|
||||
|
### IMPORTANT: Plugin Source Change |
||||
|
|
||||
|
**This change must be applied to the plugin source repository**, not the host app. The file is located in the `@timesafari/daily-notification-plugin` package. |
||||
|
|
||||
|
### File to Modify |
||||
|
|
||||
|
**Plugin Source Repository:** |
||||
|
`android/src/main/java/com/timesafari/dailynotification/DailyNotificationWorker.java` |
||||
|
|
||||
|
**Note:** In the host app's `node_modules`, this file is located at: |
||||
|
`node_modules/@timesafari/daily-notification-plugin/android/src/main/java/com/timesafari/dailynotification/DailyNotificationWorker.java` |
||||
|
|
||||
|
However, changes to `node_modules` will be overwritten on the next `npm install`. This fix must be applied to the plugin's source repository. |
||||
|
|
||||
|
### Change Required |
||||
|
|
||||
|
In the `handleDismissNotification()` method (around line 177-206), add code to cancel the notification from NotificationManager: |
||||
|
|
||||
|
```java |
||||
|
private Result handleDismissNotification(String notificationId) { |
||||
|
Trace.beginSection("DN:dismiss"); |
||||
|
try { |
||||
|
Log.d(TAG, "DN|DISMISS_START id=" + notificationId); |
||||
|
|
||||
|
// Cancel the notification from NotificationManager FIRST |
||||
|
// This ensures the notification disappears immediately when dismissed |
||||
|
NotificationManager notificationManager = |
||||
|
(NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); |
||||
|
if (notificationManager != null) { |
||||
|
int systemNotificationId = notificationId.hashCode(); |
||||
|
notificationManager.cancel(systemNotificationId); |
||||
|
Log.d(TAG, "DN|DISMISS_CANCEL_NOTIF systemId=" + systemNotificationId); |
||||
|
} |
||||
|
|
||||
|
// Remove from Room if present; also remove from legacy storage for compatibility |
||||
|
try { |
||||
|
DailyNotificationStorageRoom room = new DailyNotificationStorageRoom(getApplicationContext()); |
||||
|
// No direct delete DAO exposed via service; legacy removal still applied |
||||
|
} catch (Exception ignored) { } |
||||
|
DailyNotificationStorage storage = new DailyNotificationStorage(getApplicationContext()); |
||||
|
storage.removeNotification(notificationId); |
||||
|
|
||||
|
// Cancel any pending alarms |
||||
|
DailyNotificationScheduler scheduler = new DailyNotificationScheduler( |
||||
|
getApplicationContext(), |
||||
|
(android.app.AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE) |
||||
|
); |
||||
|
scheduler.cancelNotification(notificationId); |
||||
|
|
||||
|
Log.i(TAG, "DN|DISMISS_OK id=" + notificationId); |
||||
|
return Result.success(); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "DN|DISMISS_ERR exception id=" + notificationId + " err=" + e.getMessage(), e); |
||||
|
return Result.retry(); |
||||
|
} finally { |
||||
|
Trace.endSection(); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### Key Points |
||||
|
|
||||
|
1. **Notification ID**: Use `notificationId.hashCode()` to match the ID used when displaying (line 440: `int notificationId = content.getId().hashCode()`) |
||||
|
2. **Order**: Cancel the notification FIRST, before removing from storage, so it disappears immediately |
||||
|
3. **Null check**: Check that NotificationManager is not null before calling cancel() |
||||
|
4. **Logging**: Add instrumentation log to track cancellation |
||||
|
|
||||
|
### Expected Behavior After Fix |
||||
|
|
||||
|
1. User clicks "Dismiss" button → Notification disappears immediately from system tray |
||||
|
2. User clicks notification body → App launches (unchanged behavior) |
||||
|
3. User swipes notification away → Notification dismissed (Android handles this automatically with `setAutoCancel(true)`) |
||||
|
|
||||
|
## Testing Checklist |
||||
|
|
||||
|
- [ ] Click dismiss button → Notification disappears immediately |
||||
|
- [ ] Click notification body → App launches |
||||
|
- [ ] Swipe notification away → Notification dismissed |
||||
|
- [ ] Check logs for `DN|DISMISS_CANCEL_NOTIF` entry |
||||
|
- [ ] Verify notification is removed from storage after dismiss |
||||
|
- [ ] Verify alarms are cancelled after dismiss |
||||
|
|
||||
|
## Related Code |
||||
|
|
||||
|
- Notification display: `DailyNotificationWorker.displayNotification()` line 440 |
||||
|
- Notification ID generation: `content.getId().hashCode()` |
||||
|
- Auto-cancel: `builder.setAutoCancel(true)` line 363 (handles swipe-to-dismiss) |
||||
Loading…
Reference in new issue