DiagnosticoAlarmasAndroid already collected six raw reliability fields but only three ever reached the UI. Add a pure-Dart mapping that turns the raw snapshot into five ordered signals with a clear ok/needs- attention state (exact alarms, notifications, full-screen intent, battery-optimization exemption, native pending-alarm count), plus a manufacturer check for vendors known to require manually enabling Autostart (Xiaomi/Redmi/POCO, Huawei, Oppo, Vivo, OnePlus, Samsung), since there is no public API to detect or grant that setting.
120 lines
4.3 KiB
Dart
120 lines
4.3 KiB
Dart
import 'servicio_alarmas_android.dart';
|
|
|
|
/// One diagnosable Android alarm-reliability signal (fix/alarmas-fiabilidad).
|
|
///
|
|
/// [DiagnosticoAlarmasAndroid] already collects six raw fields, but only
|
|
/// three were ever surfaced in the UI -- the two most diagnostic ones
|
|
/// (battery-optimization exemption and the native pending-alarm count) were
|
|
/// gathered and thrown away. This module maps the raw snapshot into a
|
|
/// stable, ordered list of user-facing signals with a clear ok/needs-
|
|
/// attention state, decoupled from Flutter/localization so it stays a
|
|
/// trivial pure-Dart unit to test.
|
|
enum SenalDiagnosticoAlarma {
|
|
alarmasExactas,
|
|
notificaciones,
|
|
pantallaCompleta,
|
|
optimizacionBateria,
|
|
alarmasNativasPendientes,
|
|
}
|
|
|
|
enum EstadoSenalDiagnostico { ok, atencion }
|
|
|
|
/// The system screen a "fix this" action should open for a given signal.
|
|
/// `ninguna` marks signals with no actionable system screen of their own
|
|
/// (`alarmasNativasPendientes` is informational -- fixing the OTHER signals
|
|
/// above is what makes it recover).
|
|
enum AccionDiagnosticoAlarma {
|
|
abrirAlarmasExactas,
|
|
abrirNotificaciones,
|
|
abrirOptimizacionBateria,
|
|
abrirPantallaCompleta,
|
|
ninguna,
|
|
}
|
|
|
|
class ItemDiagnosticoAlarma {
|
|
const ItemDiagnosticoAlarma({
|
|
required this.senal,
|
|
required this.estado,
|
|
required this.accion,
|
|
});
|
|
|
|
final SenalDiagnosticoAlarma senal;
|
|
final EstadoSenalDiagnostico estado;
|
|
final AccionDiagnosticoAlarma accion;
|
|
|
|
bool get requiereAtencion => estado == EstadoSenalDiagnostico.atencion;
|
|
}
|
|
|
|
/// Builds the five diagnosable signals in a FIXED, stable order so the
|
|
/// screen renders them consistently every time.
|
|
///
|
|
/// [hayAlarmasActivas] contextualizes `alarmasNativasPendientes`: a fresh
|
|
/// install with zero alarms turned on has nothing to register with the OS,
|
|
/// so a `0` count there is only meaningful once the user actually has an
|
|
/// active alarm -- THAT combination is direct evidence the alarm never
|
|
/// reached the operating system at all, which is the single most useful
|
|
/// signal for the reported "alarm never rings" failure mode.
|
|
List<ItemDiagnosticoAlarma> construirItemsDiagnosticoAlarmas({
|
|
required DiagnosticoAlarmasAndroid diagnostico,
|
|
required bool hayAlarmasActivas,
|
|
}) {
|
|
EstadoSenalDiagnostico desde(bool ok) =>
|
|
ok ? EstadoSenalDiagnostico.ok : EstadoSenalDiagnostico.atencion;
|
|
|
|
final alarmasNativasOk =
|
|
!hayAlarmasActivas || diagnostico.alarmasNativasPendientes > 0;
|
|
|
|
return [
|
|
ItemDiagnosticoAlarma(
|
|
senal: SenalDiagnosticoAlarma.alarmasExactas,
|
|
estado: desde(diagnostico.puedeProgramarExactas),
|
|
accion: AccionDiagnosticoAlarma.abrirAlarmasExactas,
|
|
),
|
|
ItemDiagnosticoAlarma(
|
|
senal: SenalDiagnosticoAlarma.notificaciones,
|
|
estado: desde(diagnostico.notificacionesPermitidas),
|
|
accion: AccionDiagnosticoAlarma.abrirNotificaciones,
|
|
),
|
|
ItemDiagnosticoAlarma(
|
|
senal: SenalDiagnosticoAlarma.pantallaCompleta,
|
|
estado: desde(diagnostico.puedeUsarPantallaCompleta),
|
|
accion: AccionDiagnosticoAlarma.abrirPantallaCompleta,
|
|
),
|
|
ItemDiagnosticoAlarma(
|
|
senal: SenalDiagnosticoAlarma.optimizacionBateria,
|
|
estado: desde(diagnostico.ignoraOptimizacionBateria),
|
|
accion: AccionDiagnosticoAlarma.abrirOptimizacionBateria,
|
|
),
|
|
ItemDiagnosticoAlarma(
|
|
senal: SenalDiagnosticoAlarma.alarmasNativasPendientes,
|
|
estado: desde(alarmasNativasOk),
|
|
accion: AccionDiagnosticoAlarma.ninguna,
|
|
),
|
|
];
|
|
}
|
|
|
|
/// Manufacturers/sub-brands known for aggressive background-process killing
|
|
/// that requires the user to manually enable "Autostart" (or the vendor's
|
|
/// own equivalent toggle) -- there is NO public Android API to detect or
|
|
/// grant this setting programmatically, so the app can only explain it.
|
|
const _fabricantesConGuiaAutostart = [
|
|
'xiaomi',
|
|
'redmi',
|
|
'poco',
|
|
'huawei',
|
|
'oppo',
|
|
'vivo',
|
|
'oneplus',
|
|
'samsung',
|
|
];
|
|
|
|
/// Whether [fabricante] (`Build.MANUFACTURER`, e.g. "Xiaomi", "POCO") is a
|
|
/// known aggressive-background-killer vendor that needs the manual autostart
|
|
/// explanation. Case-insensitive substring match, since `Build.MANUFACTURER`
|
|
/// values are not fully standardized across sub-brands/regions/builds.
|
|
bool fabricanteRequiereGuiaAutostart(String fabricante) {
|
|
final normalizado = fabricante.trim().toLowerCase();
|
|
if (normalizado.isEmpty) return false;
|
|
return _fabricantesConGuiaAutostart.any(normalizado.contains);
|
|
}
|