diff --git a/extendedSample/src/main/java/info/mqtt/android/extsample/internal/MqttCallbackHandler.kt b/extendedSample/src/main/java/info/mqtt/android/extsample/internal/MqttCallbackHandler.kt index d14f320f..bec48cd6 100755 --- a/extendedSample/src/main/java/info/mqtt/android/extsample/internal/MqttCallbackHandler.kt +++ b/extendedSample/src/main/java/info/mqtt/android/extsample/internal/MqttCallbackHandler.kt @@ -22,12 +22,11 @@ internal class MqttCallbackHandler(private val context: Context, private val cli val connection = getInstance(context).getConnection(clientHandle) connection?.addHistory("Connection Lost [${cause?.message}]") connection?.changeConnectionStatus(Connection.ConnectionStatus.DISCONNECTED) - - val intent = Intent() - intent.setClassName(context, activityClass) - intent.putExtra("handle", clientHandle) - cause?.let { + val intent = Intent() + intent.setClassName(context, activityClass) + intent.putExtra("handle", clientHandle) + notification(context, "id=${connection?.id} host=${connection?.hostName}", intent, R.string.notifyTitle_connectionLost) } } diff --git a/serviceLibrary/src/main/java/info/mqtt/android/service/MqttAndroidClient.kt b/serviceLibrary/src/main/java/info/mqtt/android/service/MqttAndroidClient.kt index 2b38e628..7eff8ba5 100755 --- a/serviceLibrary/src/main/java/info/mqtt/android/service/MqttAndroidClient.kt +++ b/serviceLibrary/src/main/java/info/mqtt/android/service/MqttAndroidClient.kt @@ -1,6 +1,8 @@ package info.mqtt.android.service +import android.app.ActivityManager import android.content.* +import android.os.Build import android.os.Bundle import android.os.IBinder import android.util.SparseArray @@ -197,7 +199,13 @@ class MqttAndroidClient @JvmOverloads constructor( * The actual connection depends on the service, which we start and bind to here, but which we can't actually use until the serviceConnection * onServiceConnected() method has run (asynchronously), so the connection itself takes place in the onServiceConnected() method */ - if (mqttService == null) { // First time - must bind to the service + val isRunning = isMqServiceRunning() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Timber.d("isRunning=$isRunning ${mqttService?.connections?.size} foregroundServiceType=${mqttService?.foregroundServiceType}") + } else + Timber.d("isRunning=$isRunning ${mqttService?.connections?.size}") + + if (mqttService == null || mqttService?.connections?.size == 0) { // First time - must bind to the service val serviceStartIntent = Intent() serviceStartIntent.setClassName(context, SERVICE_NAME) var service: Any? = null @@ -228,6 +236,12 @@ class MqttAndroidClient @JvmOverloads constructor( return token } + private fun isMqServiceRunning(): Boolean { + val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + return manager.getRunningServices(Integer.MAX_VALUE) + .any { it.service.className == SERVICE_NAME } + } + private fun collect() { if (mqttService == null) { return @@ -246,13 +260,13 @@ class MqttAndroidClient @JvmOverloads constructor( */ private fun doConnect() { if (clientHandle == null) { - clientHandle = mqttService!!.getClient(serverURI, clientId, context.applicationInfo.packageName, persistence) + clientHandle = mqttService?.getClient(serverURI, clientId, context.applicationInfo.packageName, persistence) } - mqttService!!.isTraceEnabled = traceEnabled - mqttService!!.setTraceCallbackId(clientHandle) + mqttService?.isTraceEnabled = traceEnabled + mqttService?.setTraceCallbackId(clientHandle) val activityToken = storeToken(connectToken) try { - mqttService!!.connect(clientHandle!!, clientConnectOptions, activityToken) + mqttService?.connect(clientHandle!!, clientConnectOptions, activityToken) } catch (e: Exception) { val listener = connectToken!!.actionCallback listener?.onFailure(connectToken, e) @@ -270,9 +284,26 @@ class MqttAndroidClient @JvmOverloads constructor( * @see .disconnect */ override fun disconnect(): IMqttToken { + val isRunning = isMqServiceRunning() + Timber.d("isRunning=$isRunning ${mqttService?.connections?.size}") + val token: IMqttToken = MqttTokenAndroid(this, null, null) val activityToken = storeToken(token) - mqttService!!.disconnect(clientHandle!!, null, activityToken) + clientHandle?.let { + mqttService?.disconnect(it, null, activityToken) + } + + // if there are no more connections, we can shutdown the service + if (mqttService?.connections?.isEmpty() == true) { + Timber.d("Shutdown service") + // For < Android O this should work (untested) + val myService = Intent(context, MqttService::class.java) + context.stopService(myService) + // For Android O it's probably enough + mqttService!!.stopForeground(true) + + //unregisterResources() + } return token } @@ -292,7 +323,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun disconnect(quiesceTimeout: Long): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, null, null) val activityToken = storeToken(token) - mqttService!!.disconnect(clientHandle!!, quiesceTimeout, null, activityToken) + mqttService?.disconnect(clientHandle!!, quiesceTimeout, null, activityToken) return token } @@ -310,7 +341,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun disconnect(userContext: Any?, callback: IMqttActionListener?): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback) val activityToken = storeToken(token) - mqttService!!.disconnect(clientHandle!!, null, activityToken) + mqttService?.disconnect(clientHandle!!, null, activityToken) return token } @@ -344,7 +375,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun disconnect(quiesceTimeout: Long, userContext: Any?, callback: IMqttActionListener): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback) val activityToken = storeToken(token) - mqttService!!.disconnect(clientHandle!!, quiesceTimeout, null, activityToken) + mqttService?.disconnect(clientHandle!!, quiesceTimeout, null, activityToken) return token } @@ -405,7 +436,7 @@ class MqttAndroidClient @JvmOverloads constructor( message.isRetained = retained val token = MqttDeliveryTokenAndroid(this, userContext, callback, message) val activityToken = storeToken(token) - val internalToken = mqttService!!.publish(clientHandle!!, topic, payload, QoS.valueOf(qos), retained, null, activityToken) + val internalToken = mqttService?.publish(clientHandle!!, topic, payload, QoS.valueOf(qos), retained, null, activityToken) token.setDelegate(internalToken) return token } @@ -467,7 +498,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun publish(topic: String, message: MqttMessage, userContext: Any?, callback: IMqttActionListener?): IMqttDeliveryToken { val token = MqttDeliveryTokenAndroid(this, userContext, callback, message) val activityToken = storeToken(token) - val internalToken = mqttService!!.publish(clientHandle!!, topic, message, null, activityToken) + val internalToken = mqttService?.publish(clientHandle!!, topic, message, null, activityToken) token.setDelegate(internalToken) return token } @@ -519,7 +550,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun subscribe(topic: String, qos: Int, userContext: Any?, callback: IMqttActionListener?): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback, arrayOf(topic)) val activityToken = storeToken(token) - mqttService!!.subscribe(clientHandle!!, topic, QoS.valueOf(qos), null, activityToken) + mqttService?.subscribe(clientHandle!!, topic, QoS.valueOf(qos), null, activityToken) return token } @@ -623,7 +654,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun subscribe(topic: Array, qos: IntArray, userContext: Any?, callback: IMqttActionListener?): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback, topic) val activityToken = storeToken(token) - mqttService!!.subscribe(clientHandle!!, topic, qos, null, activityToken) + mqttService?.subscribe(clientHandle!!, topic, qos, null, activityToken) return token } @@ -702,7 +733,7 @@ class MqttAndroidClient @JvmOverloads constructor( ): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback, topicFilters) val activityToken = storeToken(token) - mqttService!!.subscribe(clientHandle!!, topicFilters, qos.map { QoS.valueOf(it) }.toTypedArray(), null, activityToken, messageListeners) + mqttService?.subscribe(clientHandle!!, topicFilters, qos.map { QoS.valueOf(it) }.toTypedArray(), null, activityToken, messageListeners) return token } @@ -740,7 +771,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun unsubscribe(topic: String, userContext: Any?, callback: IMqttActionListener?): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback) val activityToken = storeToken(token) - mqttService!!.unsubscribe(clientHandle!!, topic, null, activityToken) + mqttService?.unsubscribe(clientHandle!!, topic, null, activityToken) return token } @@ -771,7 +802,7 @@ class MqttAndroidClient @JvmOverloads constructor( override fun unsubscribe(topic: Array, userContext: Any?, callback: IMqttActionListener?): IMqttToken { val token: IMqttToken = MqttTokenAndroid(this, userContext, callback) val activityToken = storeToken(token) - mqttService!!.unsubscribe(clientHandle!!, topic, null, activityToken) + mqttService?.unsubscribe(clientHandle!!, topic, null, activityToken) return token } @@ -905,7 +936,7 @@ class MqttAndroidClient @JvmOverloads constructor( } else if (MqttServiceConstants.TRACE_ACTION == action) { traceAction(data) } else { - mqttService!!.traceError("Callback action doesn't exist.") + mqttService?.traceError("Callback action doesn't exist.") } } @@ -920,7 +951,7 @@ class MqttAndroidClient @JvmOverloads constructor( */ fun acknowledgeMessage(messageId: String): Boolean { if (messageAck == Ack.MANUAL_ACK) { - val status = mqttService!!.acknowledgeMessageArrival(clientHandle!!, messageId) + val status = mqttService?.acknowledgeMessageArrival(clientHandle!!, messageId) return status == Status.OK } return false @@ -1010,7 +1041,7 @@ class MqttAndroidClient @JvmOverloads constructor( (token as MqttTokenAndroid).notifyFailure(exceptionThrown) } } else { - mqttService!!.traceError("simpleAction : token is null") + mqttService?.traceError("simpleAction : token is null") } } @@ -1068,7 +1099,7 @@ class MqttAndroidClient @JvmOverloads constructor( callbacksList.forEach { callback -> callback.messageArrived(destinationName, message) } - mqttService!!.acknowledgeMessageArrival(clientHandle!!, messageId) + mqttService?.acknowledgeMessageArrival(clientHandle!!, messageId) } else { message.messageId = messageId callbacksList.forEach { callback -> @@ -1077,7 +1108,7 @@ class MqttAndroidClient @JvmOverloads constructor( } } catch (e: Exception) { Timber.e("failed: $e") - mqttService!!.traceError("messageArrivedAction failed: $e") + mqttService?.traceError("messageArrivedAction failed: $e") } } @@ -1145,7 +1176,7 @@ class MqttAndroidClient @JvmOverloads constructor( * @param bufferOpts the DisconnectedBufferOptions */ override fun setBufferOpts(bufferOpts: DisconnectedBufferOptions) { - mqttService!!.setBufferOpts(clientHandle!!, bufferOpts) + mqttService?.setBufferOpts(clientHandle!!, bufferOpts) } override fun getBufferedMessageCount(): Int { @@ -1157,7 +1188,7 @@ class MqttAndroidClient @JvmOverloads constructor( } override fun deleteBufferedMessage(bufferIndex: Int) { - mqttService!!.deleteBufferedMessage(clientHandle!!, bufferIndex) + mqttService?.deleteBufferedMessage(clientHandle!!, bufferIndex) } override fun getInFlightMessageCount() = 0