fix: refresh UI on app resume after force-stop recovery

- Add visibility change handler to refresh UI when app becomes visible
- Check for recent notifications and show indicator if notification was received
- Update lastKnownNextNotificationTime on app resume
- Auto-enable fire verification in Test 1 if alarm is within 5 minutes

Previously, after force-stop recovery:
- UI only refreshed on page load (which doesn't fire again after force-stop)
- Notification received indicator didn't show if notification fired while app was stopped
- Test 1 didn't verify that restored alarms actually fire

The fix:
- Listen for visibilitychange event to detect app resume
- Refresh all status displays (plugin, permissions, channel) when app becomes visible
- Check for notifications received in last 2 minutes and show indicator
- Wait 1 second after visibility change to allow recovery to complete
- Test 1 now automatically verifies restored alarms fire if within 5 minutes

This ensures the UI stays in sync after force-stop recovery and shows
notification indicators for notifications that fired while the app was stopped.
This commit is contained in:
Matthew Raymer
2025-12-30 08:58:11 +00:00
parent 4c1281754e
commit d913f03e23
2 changed files with 97 additions and 28 deletions
+29 -10
View File
@@ -1221,28 +1221,44 @@ main() {
evidence_block "test1_force_stop_recovery" evidence_block "test1_force_stop_recovery"
# Optional: Verify alarm fires (controlled by VERIFY_FIRE flag) # Verify alarm fires if it's scheduled within reasonable time window (< 5 minutes)
if [ "${VERIFY_FIRE}" = "true" ] && [ -n "${alarm_trigger_ms}" ] && [ "${goto_test1_end}" != "true" ]; then # This ensures restored alarms actually work, not just that they were restored
substep "Step 8: Verify alarm fires at scheduled time (optional)" if [ -n "${alarm_trigger_ms}" ] && [ "${goto_test1_end}" != "true" ]; then
local current_time_sec current_time_ms wait_ms wait_sec local current_time_sec current_time_ms wait_ms wait_sec
current_time_sec=$(get_current_time) current_time_sec=$(get_current_time)
current_time_ms=$((current_time_sec * 1000)) current_time_ms=$((current_time_sec * 1000))
wait_ms=$((alarm_trigger_ms - current_time_ms)) wait_ms=$((alarm_trigger_ms - current_time_ms))
# Auto-enable fire verification if alarm is within 5 minutes (300 seconds)
# Or if VERIFY_FIRE is explicitly set to true
local should_verify_fire=false
if [ "${VERIFY_FIRE}" = "true" ]; then
should_verify_fire=true
elif [ "${wait_ms}" -gt 0 ] && [ "${wait_ms}" -lt 300000 ]; then
# Alarm is in the future and within 5 minutes - auto-verify
should_verify_fire=true
fi
if [ "${should_verify_fire}" = "true" ]; then
substep "Step 8: Verify restored alarm fires at scheduled time"
set_test_context "phase1" "phase1_test1" "p1_t1_s6"
if [ "${wait_ms}" -lt 0 ]; then if [ "${wait_ms}" -lt 0 ]; then
warn "Alarm time already passed (${wait_ms} ms ago); skipping fire verification" step_warn "p1_t1_s6" "Alarm time already passed"
warn "Alarm time already passed (${wait_ms} ms ago); cannot verify fire"
else else
wait_sec=$((wait_ms / 1000)) wait_sec=$((wait_ms / 1000))
# Clamp upper bound to prevent accidentally waiting 30+ minutes # Clamp upper bound to prevent accidentally waiting too long
if [ "${wait_sec}" -gt 600 ]; then if [ "${wait_sec}" -gt 600 ]; then
step_warn "p1_t1_s6" "Alarm too far in future"
warn "Alarm is >10 minutes away (${wait_sec}s); skipping fire verification" warn "Alarm is >10 minutes away (${wait_sec}s); skipping fire verification"
info "To test fire verification, schedule alarm closer to current time" info "To test fire verification, schedule alarm closer to current time"
else else
info "Alarm scheduled for: ${alarm_readable}" step_start "p1_t1_s6" "Waiting for restored alarm to fire"
info "Restored alarm scheduled for: ${alarm_readable}"
info "Current time: $(date -d "@${current_time_sec}" 2>/dev/null || echo "${current_time_sec}")" info "Current time: $(date -d "@${current_time_sec}" 2>/dev/null || echo "${current_time_sec}")"
info "Waiting ~${wait_sec} seconds for alarm to fire..." info "Waiting ~${wait_sec} seconds for restored alarm to fire..."
clear_logs clear_logs
sleep ${wait_sec} sleep ${wait_sec}
@@ -1253,15 +1269,18 @@ main() {
alarm_fired="$($ADB_BIN logcat -d | grep -E "DNP-RECEIVE|DNP-NOTIFY|DNP-WORK|Alarm fired|Notification displayed" | tail -10)" alarm_fired="$($ADB_BIN logcat -d | grep -E "DNP-RECEIVE|DNP-NOTIFY|DNP-WORK|Alarm fired|Notification displayed" | tail -10)"
if [ -n "${alarm_fired}" ]; then if [ -n "${alarm_fired}" ]; then
ok "Alarm fired! Logs:" step_pass "p1_t1_s6" "Restored alarm fired successfully"
ok "✅ Restored alarm fired! Logs:"
echo "${alarm_fired}" echo "${alarm_fired}"
else else
warn "No alarm fire logs found" step_fail "p1_t1_s6" "Restored alarm did not fire"
warn "⚠️ No alarm fire logs found - restored alarm may not have fired"
info "Check notification tray manually or review recent logs" info "Check notification tray manually or review recent logs"
fi fi
fi fi
fi fi
fi fi
fi
fi # End of "if goto_test1_end != true" block fi # End of "if goto_test1_end != true" block
+50
View File
@@ -590,6 +590,56 @@
}, 500); }, 500);
}); });
// Refresh UI when app comes back to foreground (after force-stop, app resume, etc.)
// This ensures the UI updates after recovery from force-stop
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
console.log('[Visibility] App became visible, refreshing UI status...');
// Small delay to allow recovery to complete
setTimeout(() => {
loadPluginStatus();
loadPermissionStatus();
loadChannelStatus();
// Also check for recent notifications that might have been missed
if (window.DailyNotification) {
window.DailyNotification.getNotificationStatus()
.then(result => {
// Check if a notification was received recently (within last 2 minutes)
if (result.lastNotificationTime) {
const lastTime = new Date(result.lastNotificationTime);
const now = new Date();
const timeDiff = now - lastTime;
if (timeDiff > 0 && timeDiff < 120000) {
console.log('[Visibility] Recent notification detected, showing indicator');
const indicator = document.getElementById('notificationReceivedIndicator');
const timeSpan = document.getElementById('notificationReceivedTime');
if (indicator && timeSpan) {
indicator.style.display = 'block';
lastTime.setSeconds(0, 0);
timeSpan.textContent = `Received at ${lastTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true })}`;
// Hide after 30 seconds
setTimeout(() => {
indicator.style.display = 'none';
}, 30000);
}
}
}
// Update last known next notification time
lastKnownNextNotificationTime = result.nextNotificationTime;
})
.catch(error => {
console.error('[Visibility] Failed to get notification status:', error);
});
}
}, 1000); // Wait 1 second for recovery to complete
}
});
console.log('Functions attached to window:', { console.log('Functions attached to window:', {