11package info.mqtt.android.service
22
3+ import android.app.ActivityManager
34import android.app.Notification
45import android.content.*
56import android.os.Build
@@ -202,7 +203,13 @@ class MqttAndroidClient @JvmOverloads constructor(
202203 * The actual connection depends on the service, which we start and bind to here, but which we can't actually use until the serviceConnection
203204 * onServiceConnected() method has run (asynchronously), so the connection itself takes place in the onServiceConnected() method
204205 */
205- if (mqttService == null ) { // First time - must bind to the service
206+ val isRunning = isMqServiceRunning()
207+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
208+ Timber .d(" isRunning=$isRunning ${mqttService?.connections?.size} foregroundServiceType=${mqttService?.foregroundServiceType} " )
209+ } else
210+ Timber .d(" isRunning=$isRunning ${mqttService?.connections?.size} " )
211+
212+ if (mqttService == null || mqttService?.connections?.size == 0 ) { // First time - must bind to the service
206213 val serviceStartIntent = Intent ()
207214 serviceStartIntent.setClassName(context, SERVICE_NAME )
208215 var service: Any? = null
@@ -239,6 +246,12 @@ class MqttAndroidClient @JvmOverloads constructor(
239246 return token
240247 }
241248
249+ private fun isMqServiceRunning (): Boolean {
250+ val manager = context.getSystemService(Context .ACTIVITY_SERVICE ) as ActivityManager
251+ return manager.getRunningServices(Integer .MAX_VALUE )
252+ .any { it.service.className == SERVICE_NAME }
253+ }
254+
242255 private fun collect () {
243256 if (mqttService == null ) {
244257 return
@@ -257,13 +270,13 @@ class MqttAndroidClient @JvmOverloads constructor(
257270 */
258271 private fun doConnect () {
259272 if (clientHandle == null ) {
260- clientHandle = mqttService!! .getClient(serverURI, clientId, context.applicationInfo.packageName, persistence)
273+ clientHandle = mqttService? .getClient(serverURI, clientId, context.applicationInfo.packageName, persistence)
261274 }
262- mqttService!! .isTraceEnabled = traceEnabled
263- mqttService!! .setTraceCallbackId(clientHandle)
275+ mqttService? .isTraceEnabled = traceEnabled
276+ mqttService? .setTraceCallbackId(clientHandle)
264277 val activityToken = storeToken(connectToken)
265278 try {
266- mqttService!! .connect(clientHandle!! , clientConnectOptions, activityToken)
279+ mqttService? .connect(clientHandle!! , clientConnectOptions, activityToken)
267280 } catch (e: Exception ) {
268281 val listener = connectToken!! .actionCallback
269282 listener?.onFailure(connectToken, e)
@@ -281,9 +294,26 @@ class MqttAndroidClient @JvmOverloads constructor(
281294 * @see .disconnect
282295 */
283296 override fun disconnect (): IMqttToken {
297+ val isRunning = isMqServiceRunning()
298+ Timber .d(" isRunning=$isRunning ${mqttService?.connections?.size} " )
299+
284300 val token: IMqttToken = MqttTokenAndroid (this , null , null )
285301 val activityToken = storeToken(token)
286- mqttService!! .disconnect(clientHandle!! , null , activityToken)
302+ clientHandle?.let {
303+ mqttService?.disconnect(it, null , activityToken)
304+ }
305+
306+ // if there are no more connections, we can shutdown the service
307+ if (mqttService?.connections?.isEmpty() == true ) {
308+ Timber .d(" Shutdown service" )
309+ // For < Android O this should work (untested)
310+ val myService = Intent (context, MqttService ::class .java)
311+ context.stopService(myService)
312+ // For Android O it's probably enough
313+ mqttService!! .stopForeground(true )
314+
315+ // unregisterResources()
316+ }
287317 return token
288318 }
289319
@@ -303,7 +333,7 @@ class MqttAndroidClient @JvmOverloads constructor(
303333 override fun disconnect (quiesceTimeout : Long ): IMqttToken {
304334 val token: IMqttToken = MqttTokenAndroid (this , null , null )
305335 val activityToken = storeToken(token)
306- mqttService!! .disconnect(clientHandle!! , quiesceTimeout, null , activityToken)
336+ mqttService? .disconnect(clientHandle!! , quiesceTimeout, null , activityToken)
307337 return token
308338 }
309339
@@ -321,7 +351,7 @@ class MqttAndroidClient @JvmOverloads constructor(
321351 override fun disconnect (userContext : Any? , callback : IMqttActionListener ? ): IMqttToken {
322352 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback)
323353 val activityToken = storeToken(token)
324- mqttService!! .disconnect(clientHandle!! , null , activityToken)
354+ mqttService? .disconnect(clientHandle!! , null , activityToken)
325355 return token
326356 }
327357
@@ -355,7 +385,7 @@ class MqttAndroidClient @JvmOverloads constructor(
355385 override fun disconnect (quiesceTimeout : Long , userContext : Any? , callback : IMqttActionListener ): IMqttToken {
356386 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback)
357387 val activityToken = storeToken(token)
358- mqttService!! .disconnect(clientHandle!! , quiesceTimeout, null , activityToken)
388+ mqttService? .disconnect(clientHandle!! , quiesceTimeout, null , activityToken)
359389 return token
360390 }
361391
@@ -416,7 +446,7 @@ class MqttAndroidClient @JvmOverloads constructor(
416446 message.isRetained = retained
417447 val token = MqttDeliveryTokenAndroid (this , userContext, callback, message)
418448 val activityToken = storeToken(token)
419- val internalToken = mqttService!! .publish(clientHandle!! , topic, payload, QoS .valueOf(qos), retained, null , activityToken)
449+ val internalToken = mqttService? .publish(clientHandle!! , topic, payload, QoS .valueOf(qos), retained, null , activityToken)
420450 token.setDelegate(internalToken)
421451 return token
422452 }
@@ -478,7 +508,7 @@ class MqttAndroidClient @JvmOverloads constructor(
478508 override fun publish (topic : String , message : MqttMessage , userContext : Any? , callback : IMqttActionListener ? ): IMqttDeliveryToken {
479509 val token = MqttDeliveryTokenAndroid (this , userContext, callback, message)
480510 val activityToken = storeToken(token)
481- val internalToken = mqttService!! .publish(clientHandle!! , topic, message, null , activityToken)
511+ val internalToken = mqttService? .publish(clientHandle!! , topic, message, null , activityToken)
482512 token.setDelegate(internalToken)
483513 return token
484514 }
@@ -530,7 +560,7 @@ class MqttAndroidClient @JvmOverloads constructor(
530560 override fun subscribe (topic : String , qos : Int , userContext : Any? , callback : IMqttActionListener ? ): IMqttToken {
531561 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback, arrayOf(topic))
532562 val activityToken = storeToken(token)
533- mqttService!! .subscribe(clientHandle!! , topic, QoS .valueOf(qos), null , activityToken)
563+ mqttService? .subscribe(clientHandle!! , topic, QoS .valueOf(qos), null , activityToken)
534564 return token
535565 }
536566
@@ -634,7 +664,7 @@ class MqttAndroidClient @JvmOverloads constructor(
634664 override fun subscribe (topic : Array <String >, qos : IntArray , userContext : Any? , callback : IMqttActionListener ? ): IMqttToken {
635665 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback, topic)
636666 val activityToken = storeToken(token)
637- mqttService!! .subscribe(clientHandle!! , topic, qos, null , activityToken)
667+ mqttService? .subscribe(clientHandle!! , topic, qos, null , activityToken)
638668 return token
639669 }
640670
@@ -713,7 +743,7 @@ class MqttAndroidClient @JvmOverloads constructor(
713743 ): IMqttToken {
714744 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback, topicFilters)
715745 val activityToken = storeToken(token)
716- mqttService!! .subscribe(clientHandle!! , topicFilters, qos.map { QoS .valueOf(it) }.toTypedArray(), null , activityToken, messageListeners)
746+ mqttService? .subscribe(clientHandle!! , topicFilters, qos.map { QoS .valueOf(it) }.toTypedArray(), null , activityToken, messageListeners)
717747 return token
718748 }
719749
@@ -751,7 +781,7 @@ class MqttAndroidClient @JvmOverloads constructor(
751781 override fun unsubscribe (topic : String , userContext : Any? , callback : IMqttActionListener ? ): IMqttToken {
752782 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback)
753783 val activityToken = storeToken(token)
754- mqttService!! .unsubscribe(clientHandle!! , topic, null , activityToken)
784+ mqttService? .unsubscribe(clientHandle!! , topic, null , activityToken)
755785 return token
756786 }
757787
@@ -782,7 +812,7 @@ class MqttAndroidClient @JvmOverloads constructor(
782812 override fun unsubscribe (topic : Array <String >, userContext : Any? , callback : IMqttActionListener ? ): IMqttToken {
783813 val token: IMqttToken = MqttTokenAndroid (this , userContext, callback)
784814 val activityToken = storeToken(token)
785- mqttService!! .unsubscribe(clientHandle!! , topic, null , activityToken)
815+ mqttService? .unsubscribe(clientHandle!! , topic, null , activityToken)
786816 return token
787817 }
788818
@@ -913,7 +943,7 @@ class MqttAndroidClient @JvmOverloads constructor(
913943 } else if (MqttServiceConstants .TRACE_ACTION == action) {
914944 traceAction(data)
915945 } else {
916- mqttService!! .traceError(" Callback action doesn't exist." )
946+ mqttService? .traceError(" Callback action doesn't exist." )
917947 }
918948 }
919949
@@ -928,7 +958,7 @@ class MqttAndroidClient @JvmOverloads constructor(
928958 */
929959 fun acknowledgeMessage (messageId : String ): Boolean {
930960 if (messageAck == Ack .MANUAL_ACK ) {
931- val status = mqttService!! .acknowledgeMessageArrival(clientHandle!! , messageId)
961+ val status = mqttService? .acknowledgeMessageArrival(clientHandle!! , messageId)
932962 return status == Status .OK
933963 }
934964 return false
@@ -1018,7 +1048,7 @@ class MqttAndroidClient @JvmOverloads constructor(
10181048 (token as MqttTokenAndroid ).notifyFailure(exceptionThrown)
10191049 }
10201050 } else {
1021- mqttService!! .traceError(" simpleAction : token is null" )
1051+ mqttService? .traceError(" simpleAction : token is null" )
10221052 }
10231053 }
10241054
@@ -1076,7 +1106,7 @@ class MqttAndroidClient @JvmOverloads constructor(
10761106 callbacksList.forEach { callback ->
10771107 callback.messageArrived(destinationName, message)
10781108 }
1079- mqttService!! .acknowledgeMessageArrival(clientHandle!! , messageId)
1109+ mqttService? .acknowledgeMessageArrival(clientHandle!! , messageId)
10801110 } else {
10811111 message.messageId = messageId
10821112 callbacksList.forEach { callback ->
@@ -1085,7 +1115,7 @@ class MqttAndroidClient @JvmOverloads constructor(
10851115 }
10861116 } catch (e: Exception ) {
10871117 Timber .e(" failed: $e " )
1088- mqttService!! .traceError(" messageArrivedAction failed: $e " )
1118+ mqttService? .traceError(" messageArrivedAction failed: $e " )
10891119 }
10901120 }
10911121
@@ -1168,7 +1198,7 @@ class MqttAndroidClient @JvmOverloads constructor(
11681198 * @param bufferOpts the DisconnectedBufferOptions
11691199 */
11701200 override fun setBufferOpts (bufferOpts : DisconnectedBufferOptions ) {
1171- mqttService!! .setBufferOpts(clientHandle!! , bufferOpts)
1201+ mqttService? .setBufferOpts(clientHandle!! , bufferOpts)
11721202 }
11731203
11741204 override fun getBufferedMessageCount (): Int {
@@ -1180,7 +1210,7 @@ class MqttAndroidClient @JvmOverloads constructor(
11801210 }
11811211
11821212 override fun deleteBufferedMessage (bufferIndex : Int ) {
1183- mqttService!! .deleteBufferedMessage(clientHandle!! , bufferIndex)
1213+ mqttService? .deleteBufferedMessage(clientHandle!! , bufferIndex)
11841214 }
11851215
11861216 override fun getInFlightMessageCount () = 0
0 commit comments