6.5 KiB
AC-Powered Kiosk Display - Final Changes Summary
Device Type: Android LED Displays (AC-Powered, Not Battery)
Key Understanding
These are permanent display installations, always plugged into power. The issue is NOT about battery drain, but about Android OS treating long-running apps as "idle" and killing them even when on AC power.
What Was Fixed
✅ 1. Accurate Uptime Tracking
Problem: Previous code calculated time since midnight, not actual app runtime Solution: Now tracks real app start time
Before:
Health check performed - App uptime: 6 hours ← WRONG (should be 14h)
After:
Health check performed - App uptime: 14h 23m (started: 2026-02-26 20:00:00) ← CORRECT
✅ 2. Kiosk Display Mode (Native Android)
Problem: App treated as regular app, killed after 14 hours of "inactivity" Solution: Added window flags to prevent Android from sleeping/killing app
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD)
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
Result: App stays in foreground, Android can't kill it for being "idle"
✅ 3. Connection Health Monitoring
Problem: SignalR connection could die silently, no recovery Solution:
- Health check every 5 minutes
- Track consecutive failures
- Auto-restart connection after 3 failures
if (healthCheckFailures >= 3) {
await queuingViewModel.stopHubConnection();
await Future.delayed(const Duration(seconds: 2));
await queuingViewModel.startHubConnection();
}
✅ 4. Lifecycle Event Tracking
Problem: No visibility when app goes to background or gets killed Solution: Log all lifecycle events with actual uptime
Now you'll see:
[onAppPaused] - App uptime: 14h - WARNING: App going to background!
[onAppDetached] - App uptime: 14h - CRITICAL: App being killed!
If app stays alive correctly, you should NEVER see these logs.
✅ 5. Clinic Prefix Validation
Added: isClinicPrefixAdded(String ticketNo) method
Returns true only for: "XXX W-XX" format (3 letters + space + W-)
Files Changed
lib/view_models/screen_config_view_model.dart- Fixed uptime, health checks, lifecyclelib/models/global_config_model.dart- Clinic prefix featurelib/repositories/signalR_repo.dart- Connection improvementsandroid/app/src/main/kotlin/.../MainActivity.kt- Kiosk display modeandroid/app/src/main/AndroidManifest.xml- Activity flags
Why App Was Dying (Root Cause)
Android has App Standby Buckets (Android 9+) and Doze Mode (Android 6+):
- Even on AC power, Android monitors app activity
- No user interaction = app considered "idle"
- After ~12-24 hours, Android kills "idle" apps to free memory
- This happens even on plugged-in devices!
Our Fix: Window flags tell Android "this is a kiosk display, keep it alive"
Deployment Steps
1. Build
cd /Volumes/Data/Projects/Flutter/HMG_QLine
flutter clean
flutter build apk --release
2. Deploy
adb install -r build/app/outputs/flutter-apk/app-release.apk
3. Verify
No user action needed - app auto-configures for kiosk mode
Check logs for:
MainActivity created - Kiosk display mode active
Health check performed - App uptime: 0h 5m (started: 2026-03-01 10:54:37)
Expected Behavior After Fix
| Time | Expected Log |
|---|---|
| 0-5 min | Health check performed - App uptime: 0h 5m |
| 1 hour | Health check performed - App uptime: 1h 0m |
| 14 hours | Health check performed - App uptime: 14h 0m ← CRITICAL (previously died here) |
| 24 hours | Health check performed - App uptime: 24h 0m |
| 48 hours | Health check performed - App uptime: 48h 0m |
| 60+ hours | WARNING: App running for 60+ hours - scheduling proactive restart |
What You Should NOT See
If fix works correctly:
- ❌ No
[onAppPaused]logs (means going to background) - ❌ No
[onAppDetached]logs (means being killed) - ❌ No gaps in health check logs (every 5 minutes without fail)
If App Still Dies
Scenario 1: Manufacturer-Specific Restrictions
Some Android devices (Xiaomi, Oppo, Vivo, Realme) have additional task killers:
Solution:
- Go to device Settings > Apps > QLine
- Enable "Auto-start"
- Set Battery to "No restrictions" (even though it's AC powered)
- Disable "Battery optimization"
Scenario 2: Android Doze Override Needed
# Whitelist app from doze restrictions
adb shell dumpsys deviceidle whitelist +com.example.hmg_qline.hmg_qline
# Verify
adb shell dumpsys deviceidle whitelist | grep hmg_qline
Scenario 3: Full Kiosk Mode Required
If above doesn't work, may need Device Owner Mode:
adb shell dpm set-device-owner com.example.hmg_qline/.DeviceAdminReceiver
This gives app full control over device - cannot be killed by OS.
Testing Checklist
- Deploy new APK to test device
- Check log: "MainActivity created - Kiosk display mode active"
- Verify health checks appear every 5 minutes
- Confirm uptime increments correctly (0h 5m → 0h 10m → 0h 15m)
- Wait 14 hours - verify no
[onAppPaused]or[onAppDetached]logs - Wait 24 hours - verify app still running
- Disconnect network for 15 min - verify auto-reconnection
- Check SignalR connection recovers automatically
Success Metrics
✅ Health check logs every 5 minutes without gaps ✅ Uptime shows continuously (no resets except midnight restart) ✅ Hub connection stays alive ✅ App runs past 14-hour checkpoint ✅ App runs 48+ hours continuously ✅ No lifecycle events (paused/detached) in logs
Emergency Commands
Check if app is running:
adb shell ps | grep hmg_qline
Check device idle state:
adb shell dumpsys deviceidle
Force prevent app kill:
adb shell cmd appops set com.example.hmg_qline.hmg_qline RUN_IN_BACKGROUND allow
View last 100 logs:
adb logcat -t 100 | grep MainActivity
Contact for Issues
If app still dies after these changes, provide:
- Last 200 lines of logs before app stopped
- Android version and device model
- Screenshot of Apps > QLine > Battery settings
- Output of:
adb shell dumpsys deviceidle whitelist