├── .gitignore ├── LICENSE ├── README.md ├── lib └── org.eclipse.paho.client.mqttv3.jar └── src └── com └── jessefarebro └── mqtt └── MqttService.java /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Eclipse project files 19 | .classpath 20 | .project 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 16 | 17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 18 | 19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 20 | 21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 22 | 23 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 24 | 25 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 26 | 27 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 28 | 29 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 30 | 31 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 32 | 33 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 34 | 35 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 36 | 37 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 38 | 39 | You must cause any modified files to carry prominent notices stating that You changed the files; and 40 | 41 | You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 42 | 43 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 44 | 45 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 46 | 47 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 48 | 49 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 50 | 51 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 52 | 53 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 54 | 55 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATED 2 | ========================= 3 | I would strongly recommend using the official [Paho Android client](http://www.eclipse.org/paho/clients/android/). 4 | 5 | Setup 6 | ---- 7 | * Make sure to add the service to your AndroidManifest.xml 8 | * Edit the appropriate fields in the class with the information required 9 | 10 | Simple Example 11 | ---- 12 | ```xml 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ``` 28 | 29 | 30 | License 31 | ------- 32 | 33 | Copyright 2013 Jesse Farebrother 34 | 35 | Licensed under the Apache License, Version 2.0 (the "License"); 36 | you may not use this file except in compliance with the License. 37 | You may obtain a copy of the License at 38 | 39 | http://www.apache.org/licenses/LICENSE-2.0 40 | 41 | Unless required by applicable law or agreed to in writing, software 42 | distributed under the License is distributed on an "AS IS" BASIS, 43 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 44 | See the License for the specific language governing permissions and 45 | limitations under the License. 46 | -------------------------------------------------------------------------------- /lib/org.eclipse.paho.client.mqttv3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseFarebro/android-mqtt-service/2d18d584d281c1ac1e3c2bc0fbb9830151582ec7/lib/org.eclipse.paho.client.mqttv3.jar -------------------------------------------------------------------------------- /src/com/jessefarebro/mqtt/MqttService.java: -------------------------------------------------------------------------------- 1 | package com.jessefarebro.mqtt; 2 | 3 | import java.util.Locale; 4 | 5 | import org.eclipse.paho.client.mqttv3.MqttCallback; 6 | import org.eclipse.paho.client.mqttv3.MqttClient; 7 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions; 8 | import org.eclipse.paho.client.mqttv3.MqttDefaultFilePersistence; 9 | import org.eclipse.paho.client.mqttv3.MqttDeliveryToken; 10 | import org.eclipse.paho.client.mqttv3.MqttException; 11 | import org.eclipse.paho.client.mqttv3.MqttMessage; 12 | import org.eclipse.paho.client.mqttv3.MqttPersistenceException; 13 | import org.eclipse.paho.client.mqttv3.MqttTopic; 14 | import org.eclipse.paho.client.mqttv3.internal.MemoryPersistence; 15 | 16 | import android.app.AlarmManager; 17 | import android.app.PendingIntent; 18 | import android.app.Service; 19 | import android.content.BroadcastReceiver; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.IntentFilter; 23 | import android.net.ConnectivityManager; 24 | import android.net.NetworkInfo; 25 | import android.os.Handler; 26 | import android.os.HandlerThread; 27 | import android.os.IBinder; 28 | import android.provider.Settings.Secure; 29 | import android.util.Log; 30 | 31 | 32 | public class MqttService extends Service implements MqttCallback 33 | { 34 | public static final String DEBUG_TAG = "MqttService"; // Debug TAG 35 | 36 | private static final String MQTT_THREAD_NAME = "MqttService[" + DEBUG_TAG + "]"; // Handler Thread ID 37 | 38 | private static final String MQTT_BROKER = "m2m.eclipse.org"; // Broker URL or IP Address 39 | private static final int MQTT_PORT = 1883; // Broker Port 40 | 41 | public static final int MQTT_QOS_0 = 0; // QOS Level 0 ( Delivery Once no confirmation ) 42 | public static final int MQTT_QOS_1 = 1; // QOS Level 1 ( Delevery at least Once with confirmation ) 43 | public static final int MQTT_QOS_2 = 2; // QOS Level 2 ( Delivery only once with confirmation with handshake ) 44 | 45 | private static final int MQTT_KEEP_ALIVE = 240000; // KeepAlive Interval in MS 46 | private static final String MQTT_KEEP_ALIVE_TOPIC_FORAMT = "/users/%s/keepalive"; // Topic format for KeepAlives 47 | private static final byte[] MQTT_KEEP_ALIVE_MESSAGE = { 0 }; // Keep Alive message to send 48 | private static final int MQTT_KEEP_ALIVE_QOS = MQTT_QOS_0; // Default Keepalive QOS 49 | 50 | private static final boolean MQTT_CLEAN_SESSION = true; // Start a clean session? 51 | 52 | private static final String MQTT_URL_FORMAT = "tcp://%s:%d"; // URL Format normally don't change 53 | 54 | private static final String ACTION_START = DEBUG_TAG + ".START"; // Action to start 55 | private static final String ACTION_STOP = DEBUG_TAG + ".STOP"; // Action to stop 56 | private static final String ACTION_KEEPALIVE= DEBUG_TAG + ".KEEPALIVE"; // Action to keep alive used by alarm manager 57 | private static final String ACTION_RECONNECT= DEBUG_TAG + ".RECONNECT"; // Action to reconnect 58 | 59 | 60 | private static final String DEVICE_ID_FORMAT = "andr_%s"; // Device ID Format, add any prefix you'd like 61 | // Note: There is a 23 character limit you will get 62 | // An NPE if you go over that limit 63 | private boolean mStarted = false; // Is the Client started? 64 | private String mDeviceId; // Device ID, Secure.ANDROID_ID 65 | private Handler mConnHandler; // Seperate Handler thread for networking 66 | 67 | private MqttDefaultFilePersistence mDataStore; // Defaults to FileStore 68 | private MemoryPersistence mMemStore; // On Fail reverts to MemoryStore 69 | private MqttConnectOptions mOpts; // Connection Options 70 | 71 | private MqttTopic mKeepAliveTopic; // Instance Variable for Keepalive topic 72 | 73 | private MqttClient mClient; // Mqtt Client 74 | 75 | private AlarmManager mAlarmManager; // Alarm manager to perform repeating tasks 76 | private ConnectivityManager mConnectivityManager; // To check for connectivity changes 77 | 78 | /** 79 | * Start MQTT Client 80 | * @param Context context to start the service with 81 | * @return void 82 | */ 83 | public static void actionStart(Context ctx) { 84 | Intent i = new Intent(ctx,MqttService.class); 85 | i.setAction(ACTION_START); 86 | ctx.startService(i); 87 | } 88 | /** 89 | * Stop MQTT Client 90 | * @param Context context to start the service with 91 | * @return void 92 | */ 93 | public static void actionStop(Context ctx) { 94 | Intent i = new Intent(ctx,MqttService.class); 95 | i.setAction(ACTION_STOP); 96 | ctx.startService(i); 97 | } 98 | /** 99 | * Send a KeepAlive Message 100 | * @param Context context to start the service with 101 | * @return void 102 | */ 103 | public static void actionKeepalive(Context ctx) { 104 | Intent i = new Intent(ctx,MqttService.class); 105 | i.setAction(ACTION_KEEPALIVE); 106 | ctx.startService(i); 107 | } 108 | 109 | /** 110 | * Initalizes the DeviceId and most instance variables 111 | * Including the Connection Handler, Datastore, Alarm Manager 112 | * and ConnectivityManager. 113 | */ 114 | @Override 115 | public void onCreate() { 116 | super.onCreate(); 117 | 118 | mDeviceId = String.format(DEVICE_ID_FORMAT, 119 | Secure.getString(getContentResolver(), Secure.ANDROID_ID)); 120 | 121 | HandlerThread thread = new HandlerThread(MQTT_THREAD_NAME); 122 | thread.start(); 123 | 124 | mConnHandler = new Handler(thread.getLooper()); 125 | 126 | try { 127 | mDataStore = new MqttDefaultFilePersistence(getCacheDir().getAbsolutePath()); 128 | } catch(MqttPersistenceException e) { 129 | e.printStackTrace(); 130 | mDataStore = null; 131 | mMemStore = new MemoryPersistence(); 132 | } 133 | 134 | mOpts = new MqttConnectOptions(); 135 | mOpts.setCleanSession(MQTT_CLEAN_SESSION); 136 | // Do not set keep alive interval on mOpts we keep track of it with alarm's 137 | 138 | mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 139 | mConnectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 140 | } 141 | 142 | /** 143 | * Service onStartCommand 144 | * Handles the action passed via the Intent 145 | * 146 | * @return START_REDELIVER_INTENT 147 | */ 148 | @Override 149 | public int onStartCommand(Intent intent, int flags, int startId) { 150 | super.onStartCommand(intent, flags, startId); 151 | 152 | String action = intent.getAction(); 153 | 154 | Log.i(DEBUG_TAG,"Received action of " + action); 155 | 156 | if(action == null) { 157 | Log.i(DEBUG_TAG,"Starting service with no action\n Probably from a crash"); 158 | } else { 159 | if(action.equals(ACTION_START)) { 160 | Log.i(DEBUG_TAG,"Received ACTION_START"); 161 | start(); 162 | } else if(action.equals(ACTION_STOP)) { 163 | stop(); 164 | } else if(action.equals(ACTION_KEEPALIVE)) { 165 | keepAlive(); 166 | } else if(action.equals(ACTION_RECONNECT)) { 167 | if(isNetworkAvailable()) { 168 | reconnectIfNecessary(); 169 | } 170 | } 171 | } 172 | 173 | return START_REDELIVER_INTENT; 174 | } 175 | 176 | /** 177 | * Attempts connect to the Mqtt Broker 178 | * and listen for Connectivity changes 179 | * via ConnectivityManager.CONNECTVITIY_ACTION BroadcastReceiver 180 | */ 181 | private synchronized void start() { 182 | if(mStarted) { 183 | Log.i(DEBUG_TAG,"Attempt to start while already started"); 184 | return; 185 | } 186 | 187 | if(hasScheduledKeepAlives()) { 188 | stopKeepAlives(); 189 | } 190 | 191 | connect(); 192 | 193 | registerReceiver(mConnectivityReceiver,new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 194 | } 195 | /** 196 | * Attempts to stop the Mqtt client 197 | * as well as halting all keep alive messages queued 198 | * in the alarm manager 199 | */ 200 | private synchronized void stop() { 201 | if(!mStarted) { 202 | Log.i(DEBUG_TAG,"Attemtpign to stop connection that isn't running"); 203 | return; 204 | } 205 | 206 | if(mClient != null) { 207 | mConnHandler.post(new Runnable() { 208 | @Override 209 | public void run() { 210 | try { 211 | mClient.disconnect(); 212 | } catch(MqttException ex) { 213 | ex.printStackTrace(); 214 | } 215 | mClient = null; 216 | mStarted = false; 217 | 218 | stopKeepAlives(); 219 | } 220 | }); 221 | } 222 | 223 | unregisterReceiver(mConnectivityReceiver); 224 | } 225 | /** 226 | * Connects to the broker with the appropriate datastore 227 | */ 228 | private synchronized void connect() { 229 | String url = String.format(Locale.US, MQTT_URL_FORMAT, MQTT_BROKER, MQTT_PORT); 230 | Log.i(DEBUG_TAG,"Connecting with URL: " + url); 231 | try { 232 | if(mDataStore != null) { 233 | Log.i(DEBUG_TAG,"Connecting with DataStore"); 234 | mClient = new MqttClient(url,mDeviceId,mDataStore); 235 | } else { 236 | Log.i(DEBUG_TAG,"Connecting with MemStore"); 237 | mClient = new MqttClient(url,mDeviceId,mMemStore); 238 | } 239 | } catch(MqttException e) { 240 | e.printStackTrace(); 241 | } 242 | 243 | mConnHandler.post(new Runnable() { 244 | @Override 245 | public void run() { 246 | try { 247 | mClient.connect(mOpts); 248 | 249 | mClient.subscribe("hello", 0); 250 | 251 | mClient.setCallback(MqttService.this); 252 | 253 | mStarted = true; // Service is now connected 254 | 255 | Log.i(DEBUG_TAG,"Successfully connected and subscribed starting keep alives"); 256 | 257 | startKeepAlives(); 258 | } catch(MqttException e) { 259 | e.printStackTrace(); 260 | } 261 | } 262 | }); 263 | } 264 | /** 265 | * Schedules keep alives via a PendingIntent 266 | * in the Alarm Manager 267 | */ 268 | private void startKeepAlives() { 269 | Intent i = new Intent(); 270 | i.setClass(this, MqttService.class); 271 | i.setAction(ACTION_KEEPALIVE); 272 | PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 273 | mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 274 | System.currentTimeMillis() + MQTT_KEEP_ALIVE, 275 | MQTT_KEEP_ALIVE, pi); 276 | } 277 | /** 278 | * Cancels the Pending Intent 279 | * in the alarm manager 280 | */ 281 | private void stopKeepAlives() { 282 | Intent i = new Intent(); 283 | i.setClass(this, MqttService.class); 284 | i.setAction(ACTION_KEEPALIVE); 285 | PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 286 | mAlarmManager.cancel(pi); 287 | } 288 | /** 289 | * Publishes a KeepALive to the topic 290 | * in the broker 291 | */ 292 | private synchronized void keepAlive() { 293 | if(isConnected()) { 294 | try { 295 | sendKeepAlive(); 296 | return; 297 | } catch(MqttConnectivityException ex) { 298 | ex.printStackTrace(); 299 | reconnectIfNecessary(); 300 | } catch(MqttPersistenceException ex) { 301 | ex.printStackTrace(); 302 | stop(); 303 | } catch(MqttException ex) { 304 | ex.printStackTrace(); 305 | stop(); 306 | } 307 | } 308 | } 309 | /** 310 | * Checkes the current connectivity 311 | * and reconnects if it is required. 312 | */ 313 | private synchronized void reconnectIfNecessary() { 314 | if(mStarted && mClient == null) { 315 | connect(); 316 | } 317 | } 318 | /** 319 | * Query's the NetworkInfo via ConnectivityManager 320 | * to return the current connected state 321 | * @return boolean true if we are connected false otherwise 322 | */ 323 | private boolean isNetworkAvailable() { 324 | NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); 325 | 326 | return (info == null) ? false : info.isConnected(); 327 | } 328 | /** 329 | * Verifies the client State with our local connected state 330 | * @return true if its a match we are connected false if we aren't connected 331 | */ 332 | private boolean isConnected() { 333 | if(mStarted && mClient != null && !mClient.isConnected()) { 334 | Log.i(DEBUG_TAG,"Mismatch between what we think is connected and what is connected"); 335 | } 336 | 337 | if(mClient != null) { 338 | return (mStarted && mClient.isConnected()) ? true : false; 339 | } 340 | 341 | return false; 342 | } 343 | /** 344 | * Receiver that listens for connectivity chanes 345 | * via ConnectivityManager 346 | */ 347 | private final BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() { 348 | @Override 349 | public void onReceive(Context context, Intent intent) { 350 | Log.i(DEBUG_TAG,"Connectivity Changed..."); 351 | } 352 | }; 353 | /** 354 | * Sends a Keep Alive message to the specified topic 355 | * @see MQTT_KEEP_ALIVE_MESSAGE 356 | * @see MQTT_KEEP_ALIVE_TOPIC_FORMAT 357 | * @return MqttDeliveryToken specified token you can choose to wait for completion 358 | */ 359 | private synchronized MqttDeliveryToken sendKeepAlive() 360 | throws MqttConnectivityException, MqttPersistenceException, MqttException { 361 | if(!isConnected()) 362 | throw new MqttConnectivityException(); 363 | 364 | if(mKeepAliveTopic == null) { 365 | mKeepAliveTopic = mClient.getTopic( 366 | String.format(Locale.US, MQTT_KEEP_ALIVE_TOPIC_FORAMT,mDeviceId)); 367 | } 368 | 369 | Log.i(DEBUG_TAG,"Sending Keepalive to " + MQTT_BROKER); 370 | 371 | MqttMessage message = new MqttMessage(MQTT_KEEP_ALIVE_MESSAGE); 372 | message.setQos(MQTT_KEEP_ALIVE_QOS); 373 | 374 | return mKeepAliveTopic.publish(message); 375 | } 376 | /** 377 | * Query's the AlarmManager to check if there is 378 | * a keep alive currently scheduled 379 | * @return true if there is currently one scheduled false otherwise 380 | */ 381 | private synchronized boolean hasScheduledKeepAlives() { 382 | Intent i = new Intent(); 383 | i.setClass(this, MqttService.class); 384 | i.setAction(ACTION_KEEPALIVE); 385 | PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_NO_CREATE); 386 | 387 | return (pi != null) ? true : false; 388 | } 389 | 390 | 391 | @Override 392 | public IBinder onBind(Intent arg0) { 393 | return null; 394 | } 395 | /** 396 | * Connectivity Lost from broker 397 | */ 398 | @Override 399 | public void connectionLost(Throwable arg0) { 400 | stopKeepAlives(); 401 | 402 | mClient = null; 403 | 404 | if(isNetworkAvailable()) { 405 | reconnectIfNecessary(); 406 | } 407 | } 408 | /** 409 | * Publish Message Completion 410 | */ 411 | @Override 412 | public void deliveryComplete(MqttDeliveryToken arg0) { 413 | 414 | } 415 | /** 416 | * Received Message from broker 417 | */ 418 | @Override 419 | public void messageArrived(MqttTopic topic, MqttMessage message) 420 | throws Exception { 421 | Log.i(DEBUG_TAG," Topic:\t" + topic.getName() + 422 | " Message:\t" + new String(message.getPayload()) + 423 | " QoS:\t" + message.getQos()); 424 | } 425 | /** 426 | * MqttConnectivityException Exception class 427 | */ 428 | private class MqttConnectivityException extends Exception { 429 | private static final long serialVersionUID = -7385866796799469420L; 430 | } 431 | } 432 | --------------------------------------------------------------------------------