pendingintent - La alarma exacta de Android siempre tiene 3 minutos de descanso.
alarmmanager android tutorial (1)
El problema parece ocurrir solo en dispositivos Samsung (por ejemplo, Galaxy Grand, S4, S5, S6, Nota 3, Nota 4) con Lollipop (5.0, 5.1, 5.1.1). Parece que las alarmas no están programadas cuando el dispositivo está en la batería con la pantalla apagada. Si el dispositivo se está cargando o tiene una pantalla encendida durante la programación de la alarma, el problema no se producirá.
Puedes verificar si la próxima alarma será inexacta con:
adb shell dumpsys alarm
No encontré la solución perfecta para este problema, solo soluciones donde cada una tiene algunos inconvenientes:
- Use
setAlarmClock
lugar desetExact
(vea esta respuesta ). Esto funciona muy bien (no en todos los dispositivos), pero el problema con esta solución es que la alarma afectará al sistema al mostrar el ícono de alarma en la barra de estado (si alguien ya no tiene configurado el reloj de alarma) y mostrar la próxima hora programada de alarma en widgets de alarma, etc. Desafortunadamente, mientras esto funciona en Galaxy Grand con 5.1.1, no en Galaxy S4 con 5.0.1. - Habilitar la pantalla antes de programar la alarma (hago esto medio segundo antes de programar la próxima alarma para evitar la condición de carrera). Por supuesto, no es una buena solución para cada aplicación habilitar la pantalla solo para programar la próxima alarma.
- ¡Un informe de error que describe un problema similar lo conecta con la longitud del nombre del paquete de la aplicación! No verifiqué si realmente soluciona el problema, porque cambiar el nombre del paquete no es una opción para una aplicación ya publicada.
- Hay otro informe en el que alguien afirma que esto se puede arreglar utilizando
WakefulBroadcastReceiver
, pero no funciona en mi caso.
BTW Este tema me vuelve loco :)
Edición: Parece que este problema no ocurre cuando hay una palabra clave "alarma" o "alerta" en el nombre del paquete de la aplicación (como lo señaló Mathieu H. en los comentarios a continuación).
También pude solucionar el problema manualmente al deshabilitar la optimización de la aplicación en la configuración de la batería (o en la aplicación Smart Manager). Parece que no se puede hacer mediante programación, por lo que puede intentar preguntar a sus usuarios ...
Tengo una aplicación que utiliza el AlarmManager
para AlarmManager
regularmente el teléfono a toda hora y enviar un mensaje a un reloj con Android Wear que produce una breve vibración. Tengo dos usuarios con un Samsung Galaxy S6 con Android 5.1.1 y el Sony SW 3 con 5.1.1 que experimentan un error extraño. En la primera hora completa, la vibración está en el momento exacto, pero todas las demás vibraciones se retrasan 3 minutos. A veces, incluso la primera hora completa de vibración se retrasa.
Aquí hay un código:
final Calendar time = Calendar.getInstance();
time.set(Calendar.SECOND, 0);
time.set(Calendar.MILLISECOND, 0);
time.set(Calendar.MINUTE, 0);
time.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY) + 1);
final Intent hourlyChimeIntent = new Intent(context, HourlyChimeReceiver.class);
hourlyChimeIntent.setAction(key);
final AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pi = PendingIntent.getBroadcast(context, 0, hourlyChimeIntent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setExact(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);
WakeLock
un WakeLock
en el receptor y luego envié un mensaje al reloj Wear en un hilo. No se pierde ninguna vibración, solo llegan 3 minutos tarde.
No tengo otros informes sobre este problema y todos mis dispositivos de prueba funcionan bien. Aunque no tengo un dispositivo Samsung.
¿Alguna idea de qué podría causar el retraso de 3 minutos? ¿Samsung ignora setExact
y hace que mi alarma sea inexacta? ¿Cómo forzar las alarmas exactas en Samsung?
EDITAR:
Aquí está el código específico de Android Wear. En el método onReceive
del receptor hago esto:
final PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock lock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID);
lock.acquire(7L * 1000L);
final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context).addApi(Wearable.API).build();
new Thread(new Runnable() {
@Override
public void run() {
googleApiClient.blockingConnect();
long pattern[];
pattern = new long[] {0L, 500L};
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(2000L, TimeUnit.MILLISECONDS);
if (nodes != null) {
for (final Node node : nodes.getNodes()) {
// just send and forget
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), "/hourly_chime", Utils.Vibrator.serializeVibratePattern(pattern).getBytes()).await();
}
}
}
}).start();