![JAR search and dependency download from the Maven repository](/logo.png)
org.eclipse.paho.android.service.AlarmPingSender Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttPingSender;
import org.eclipse.paho.client.mqttv3.internal.ClientComms;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
/**
* Default ping sender implementation on Android. It is based on AlarmManager.
*
* This class implements the {@link MqttPingSender} pinger interface
* allowing applications to send ping packet to server every keep alive interval.
*
*
* @see MqttPingSender
*/
class AlarmPingSender implements MqttPingSender {
// Identifier for Intents, log messages, etc..
private static final String TAG = "AlarmPingSender";
// TODO: Add log.
private ClientComms comms;
private MqttService service;
private BroadcastReceiver alarmReceiver;
private AlarmPingSender that;
private PendingIntent pendingIntent;
private volatile boolean hasStarted = false;
public AlarmPingSender(MqttService service) {
if (service == null) {
throw new IllegalArgumentException(
"Neither service nor client can be null.");
}
this.service = service;
that = this;
}
@Override
public void init(ClientComms comms) {
this.comms = comms;
this.alarmReceiver = new AlarmReceiver();
}
@Override
public void start() {
String action = MqttServiceConstants.PING_SENDER
+ comms.getClient().getClientId();
Log.d(TAG, "Register alarmreceiver to MqttService"+ action);
service.registerReceiver(alarmReceiver, new IntentFilter(action));
pendingIntent = PendingIntent.getBroadcast(service, 0, new Intent(
action), PendingIntent.FLAG_UPDATE_CURRENT);
schedule(comms.getKeepAlive());
hasStarted = true;
}
@Override
public void stop() {
Log.d(TAG, "Unregister alarmreceiver to MqttService"+comms.getClient().getClientId());
if(hasStarted){
if(pendingIntent != null){
// Cancel Alarm.
AlarmManager alarmManager = (AlarmManager) service.getSystemService(Service.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
hasStarted = false;
try{
service.unregisterReceiver(alarmReceiver);
}catch(IllegalArgumentException e){
//Ignore unregister errors.
}
}
}
@Override
public void schedule(long delayInMilliseconds) {
long nextAlarmInMilliseconds = System.currentTimeMillis()
+ delayInMilliseconds;
Log.d(TAG, "Schedule next alarm at " + nextAlarmInMilliseconds);
AlarmManager alarmManager = (AlarmManager) service
.getSystemService(Service.ALARM_SERVICE);
if(Build.VERSION.SDK_INT >= 23){
// In SDK 23 and above, dosing will prevent setExact, setExactAndAllowWhileIdle will force
// the device to run this task whilst dosing.
Log.d(TAG, "Alarm scheule using setExactAndAllowWhileIdle, next: " + delayInMilliseconds);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,
pendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
Log.d(TAG, "Alarm scheule using setExact, delay: " + delayInMilliseconds);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,
pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,
pendingIntent);
}
}
/*
* This class sends PingReq packet to MQTT broker
*/
class AlarmReceiver extends BroadcastReceiver {
private WakeLock wakelock;
private final String wakeLockTag = MqttServiceConstants.PING_WAKELOCK
+ that.comms.getClient().getClientId();
@Override
@SuppressLint("Wakelock")
public void onReceive(Context context, Intent intent) {
// According to the docs, "Alarm Manager holds a CPU wake lock as
// long as the alarm receiver's onReceive() method is executing.
// This guarantees that the phone will not sleep until you have
// finished handling the broadcast.", but this class still get
// a wake lock to wait for ping finished.
Log.d(TAG, "Sending Ping at:" + System.currentTimeMillis());
PowerManager pm = (PowerManager) service
.getSystemService(Service.POWER_SERVICE);
wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
wakelock.acquire();
// Assign new callback to token to execute code after PingResq
// arrives. Get another wakelock even receiver already has one,
// release it until ping response returns.
IMqttToken token = comms.checkForActivity(new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "Success. Release lock(" + wakeLockTag + "):"
+ System.currentTimeMillis());
//Release wakelock when it is done.
wakelock.release();
}
@Override
public void onFailure(IMqttToken asyncActionToken,
Throwable exception) {
Log.d(TAG, "Failure. Release lock(" + wakeLockTag + "):"
+ System.currentTimeMillis());
//Release wakelock when it is done.
wakelock.release();
}
});
if (token == null && wakelock.isHeld()) {
wakelock.release();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy