You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_QLine/AC_POWERED_KIOSK_SUMMARY.md

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

  1. lib/view_models/screen_config_view_model.dart - Fixed uptime, health checks, lifecycle
  2. lib/models/global_config_model.dart - Clinic prefix feature
  3. lib/repositories/signalR_repo.dart - Connection improvements
  4. android/app/src/main/kotlin/.../MainActivity.kt - Kiosk display mode
  5. android/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:

  1. Go to device Settings > Apps > QLine
  2. Enable "Auto-start"
  3. Set Battery to "No restrictions" (even though it's AC powered)
  4. 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:

  1. Last 200 lines of logs before app stopped
  2. Android version and device model
  3. Screenshot of Apps > QLine > Battery settings
  4. Output of: adb shell dumpsys deviceidle whitelist