netdiag-app/native-plugin/MonitorService.kt
Eduard Wisch d2df3ee929
All checks were successful
Build APK / build-apk (push) Successful in 1m47s
Neues Werkzeug: Geräte-Monitor (Dauerüberwachung) [apk]
Für das Kamera-Problem: mehrere Geräte auswählen und ihre Erreichbarkeit
über längere Zeit überwachen — jeder Ausfall wird mit Uhrzeit protokolliert.

- MonitorService: schlanker Vordergrund-Dienst, hält den Prozess am Leben,
  damit die Überwachung bei Display aus / App-Wechsel weiterläuft
- Plugin startMonitor/stopMonitor/getMonitorStatus: pingt die Geräte im
  gewählten Intervall, Wechsel erreichbar↔weg erzeugt ein monitorEvent;
  WifiLock gegen WLAN-Schlaf, Heads-up-Benachrichtigung bei Ausfall
- Monitor-Seite (protokoll/[id]/monitor): Geräte-Mehrfachauswahl,
  Intervallwahl, Live-Ereignisliste, frühere Überwachungen mit Ausfallzahl
- Überwachung läuft beim Verlassen der Seite weiter; Rückkehr nimmt den
  Stand wieder auf (getMonitorStatus)
- Manifest: MonitorService + FOREGROUND_SERVICE_DATA_SYNC, POST_NOTIFICATIONS
- Kachel "Geräte-Monitor" im Werkzeuge-Raster

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 23:12:26 +02:00

81 lines
2.9 KiB
Kotlin

package de.data_it_solution.netdiag
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
/**
* Schlanker Vordergrund-Dienst für den Geräte-Monitor.
*
* Er hält den App-Prozess am Leben, solange die Überwachung läuft — damit
* Android die Mess-Schleife bei ausgeschaltetem Display oder App-Wechsel nicht
* beendet. Die eigentliche Ping-Logik läuft im NetDiagScannerPlugin; dieser
* Dienst zeigt nur die dauerhafte Benachrichtigung.
*/
class MonitorService : Service() {
override fun onBind(intent: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val text = intent?.getStringExtra(EXTRA_TEXT) ?: "Geräte-Überwachung läuft"
val notification = buildNotification(text)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(NOTIF_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
} else {
startForeground(NOTIF_ID, notification)
}
return START_STICKY
}
private fun buildNotification(text: String): Notification {
ensureChannel(this)
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("NetDiag — Geräte-Monitor")
.setContentText(text)
.setSmallIcon(android.R.drawable.ic_menu_compass)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
}
companion object {
const val CHANNEL_ID = "netdiag-monitor"
const val NOTIF_ID = 4711
const val EXTRA_TEXT = "text"
/** Benachrichtigungskanal anlegen (idempotent) */
fun ensureChannel(ctx: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val mgr = ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (mgr.getNotificationChannel(CHANNEL_ID) == null) {
mgr.createNotificationChannel(
NotificationChannel(
CHANNEL_ID,
"Geräte-Monitor",
NotificationManager.IMPORTANCE_LOW,
),
)
}
}
fun start(ctx: Context, text: String) {
val i = Intent(ctx, MonitorService::class.java).putExtra(EXTRA_TEXT, text)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ctx.startForegroundService(i)
} else {
ctx.startService(i)
}
}
fun stop(ctx: Context) {
ctx.stopService(Intent(ctx, MonitorService::class.java))
}
}
}