org.eclipse.paho.android.service.MqttConnection.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.paho.android.service.MqttConnection.java

Source

/*******************************************************************************
 * Copyright (c) 1999, 2014 IBM Corp.
 * <p/>
 * 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.
 * <p/>
 * 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 android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import org.eclipse.paho.android.service.MessageStore.StoredMessage;
import org.eclipse.paho.android.service.sample.R;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * <p>
 * MqttConnection holds a MqttAsyncClient {host,port,clientId} instance to perform 
 * MQTT operations to MQTT broker.
 * </p>
 * <p>
 * Most of the major API here is intended to implement the most general forms of
 * the methods in IMqttAsyncClient, with slight adjustments for the Android
 * environment<br>
 * These adjustments usually consist of adding two parameters to each method :-
 * <ul>
 * <li>invocationContext - a string passed from the application to identify the
 * context of the operation (mainly included for support of the javascript API
 * implementation)</li>
 * <li>activityToken - a string passed from the Activity to relate back to a
 * callback method or other context-specific data</li>
 * </ul>
 * </p>
 * <p>
 * Operations are very much asynchronous, so success and failure are notified by
 * packing the relevant data into Intent objects which are broadcast back to the
 * Activity via the MqttService.callbackToActivity() method.
 * </p>
 */
class MqttConnection implements MqttCallback {

    // Strings for Intents etc..
    private static final String TAG = "MqttConnection";
    // Error status messages
    private static final String NOT_CONNECTED = "not connected";

    // fields for the connection definition
    private String serverURI;

    public String getServerURI() {
        return serverURI;
    }

    public void setServerURI(String serverURI) {
        this.serverURI = serverURI;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    private String clientId;
    private MqttClientPersistence persistence = null;
    private MqttConnectOptions connectOptions;

    public MqttConnectOptions getConnectOptions() {
        return connectOptions;
    }

    public void setConnectOptions(MqttConnectOptions connectOptions) {
        this.connectOptions = connectOptions;
    }

    // Client handle, used for callbacks...
    private String clientHandle;

    public String getClientHandle() {
        return clientHandle;
    }

    public void setClientHandle(String clientHandle) {
        this.clientHandle = clientHandle;
    }

    //store connect ActivityToken for reconnect
    private String reconnectActivityToken = null;

    // our client object - instantiated on connect
    private MqttAsyncClient myClient = null;

    // our (parent) service object
    private MqttService service = null;

    private volatile boolean disconnected = true;
    private boolean cleanSession = true;

    // Indicate this connection is connecting or not.
    // This variable uses to avoid reconnect multiple times.
    private volatile boolean isConnecting = false;

    // Saved sent messages and their corresponding Topics, activityTokens and
    // invocationContexts, so we can handle "deliveryComplete" callbacks
    // from the mqttClient
    private Map<IMqttDeliveryToken, String /* Topic */> savedTopics = new HashMap<IMqttDeliveryToken, String>();
    private Map<IMqttDeliveryToken, MqttMessage> savedSentMessages = new HashMap<IMqttDeliveryToken, MqttMessage>();
    private Map<IMqttDeliveryToken, String> savedActivityTokens = new HashMap<IMqttDeliveryToken, String>();
    private Map<IMqttDeliveryToken, String> savedInvocationContexts = new HashMap<IMqttDeliveryToken, String>();

    private WakeLock wakelock = null;
    private String wakeLockTag = null;

    /**
     * Constructor - create an MqttConnection to communicate with MQTT server
     *
     * @param service
     *            our "parent" service - we make callbacks to it
     * @param serverURI
     *            the URI of the MQTT server to which we will connect
     * @param clientId
     *            the name by which we will identify ourselves to the MQTT
     *            server
     * @param persistence
     *            the persistence class to use to store in-flight message. If
     *            null then the default persistence mechanism is used
     * @param clientHandle
     *            the "handle" by which the activity will identify us
     */
    MqttConnection(MqttService service, String serverURI, String clientId, MqttClientPersistence persistence,
            String clientHandle) {
        Log.v("mqtt", "MqttConnection");
        this.serverURI = serverURI.toString();
        this.service = service;
        this.clientId = clientId;
        this.persistence = persistence;
        this.clientHandle = clientHandle;

        StringBuffer buff = new StringBuffer(this.getClass().getCanonicalName());
        buff.append(" ");
        buff.append(clientId);
        buff.append(" ");
        buff.append("on host ");
        buff.append(serverURI);
        wakeLockTag = buff.toString();
    }

    // The major API implementation follows

    /**
     * Connect to the server specified when we were instantiated
     *
     * @param options
     *            timeout, etc
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary identifier to be passed back to the Activity
     */
    public void connect(MqttConnectOptions options, String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection connect trace 1");
        connectOptions = options;
        reconnectActivityToken = activityToken;

        if (options != null) {
            cleanSession = options.isCleanSession();
            Log.v("mqtt", "MqttConnection connect trace 2");
        }

        if (connectOptions.isCleanSession()) { // if it's a clean session,
            // discard old data
            service.messageStore.clearArrivedMessages(clientHandle);
            Log.v("mqtt", "MqttConnection connect trace 3");
        }
        Log.v("mqtt", "MqttConnection connect trace 4");
        service.traceDebug(TAG, "Connecting {" + serverURI + "} as {" + clientId + "}");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.CONNECT_ACTION);

        try {
            if (persistence == null) {
                Log.v("mqtt", "MqttConnection connect trace 5");
                // ask Android where we can put files
                File myDir = service.getExternalFilesDir(TAG);
                // Log.v("mqtt", "MqttConnection connect trace 5a "+myDir.getAbsolutePath());

                /*File myDir = new File(Environment.getExternalStorageDirectory() + "/MqttConnection");
                Log.v("mqtt","MqttConnection myDir.getAbsolutePath(): "+myDir.getAbsolutePath());
                boolean success = true;
                if (!myDir.exists()) {
                success = myDir.mkdir();
                }
                if (success) {
                // Do something on success
                } else {
                // Do something else on failure
                }*/

                if (myDir == null) {
                    // No external storage, use internal storage instead.
                    myDir = service.getDir(TAG, Context.MODE_PRIVATE);
                    Log.v("mqtt", "MqttConnection connect trace 6");
                    if (myDir == null) {
                        //Shouldn't happen.
                        Log.v("mqtt", "MqttConnection connect trace 7");
                        resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE,
                                "Error! No external and internal storage available");
                        resultBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION,
                                new MqttPersistenceException());
                        service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
                        return;
                    }
                }
                Log.v("mqtt", "MqttConnection connect trace 8");
                // use that to setup MQTT client persistence storage
                persistence = new MqttDefaultFilePersistence(myDir.getAbsolutePath());
            }

            IMqttActionListener listener = new MqttConnectionListener(resultBundle) {

                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.v("mqtt", "MqttConnection connect trace 9 onSuccess");
                    doAfterConnectSuccess(resultBundle);
                    service.traceDebug(TAG, "connect success!");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.v("mqtt", "MqttConnection connect trace 9 onFailure");
                    resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE,
                            exception.getLocalizedMessage());
                    resultBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, exception);
                    service.traceError(TAG,
                            "connect fail, call connect to reconnect.reason:" + exception.getMessage());

                    doAfterConnectFail(resultBundle);

                }
            };
            Log.v("mqtt", "MqttConnection connect trace 10");
            if (myClient != null) {
                Log.v("mqtt", "MqttConnection connect trace 11");
                if (isConnecting) {
                    Log.v("mqtt", "MqttConnection connect trace 12");
                    service.traceDebug(TAG,
                            "myClient != null and the client is connecting. Connect return directly.");
                    service.traceDebug(TAG,
                            "Connect return:isConnecting:" + isConnecting + ".disconnected:" + disconnected);
                    return;
                } else if (!disconnected) {
                    Log.v("mqtt", "MqttConnection connect trace 13");
                    service.traceDebug(TAG, "myClient != null and the client is connected and notify!");
                    doAfterConnectSuccess(resultBundle);
                } else {
                    Log.v("mqtt", "MqttConnection connect trace 14");
                    service.traceDebug(TAG, "myClient != null and the client is not connected");
                    service.traceDebug(TAG, "Do Real connect!");
                    setConnectingState(true);
                    myClient.connect(connectOptions, invocationContext, listener);
                }
            }

            // if myClient is null, then create a new connection
            else {
                Log.v("mqtt", "MqttConnection connect trace 15");
                myClient = new MqttAsyncClient(serverURI, clientId, persistence, new AlarmPingSender(service));
                myClient.setCallback(this);

                service.traceDebug(TAG, "Do Real connect!");
                setConnectingState(true);
                myClient.connect(connectOptions, invocationContext, listener);
            }
        } catch (Exception e) {
            handleException(resultBundle, e);
        }
    }

    private void doAfterConnectSuccess(final Bundle resultBundle) {
        Log.v("mqtt", "MqttConnection doAfterConnectSuccess");
        //since the device's cpu can go to sleep, acquire a wakelock and drop it later.
        acquireWakeLock();
        service.callbackToActivity(clientHandle, Status.OK, resultBundle);
        deliverBacklog();
        setConnectingState(false);
        disconnected = false;
        releaseWakeLock();
    }

    private void doAfterConnectFail(final Bundle resultBundle) {
        //
        Log.v("mqtt", "MqttConnection doAfterConnectFail");
        acquireWakeLock();
        disconnected = true;
        setConnectingState(false);
        service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        releaseWakeLock();
    }

    private void handleException(final Bundle resultBundle, Exception e) {
        resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, e.getLocalizedMessage());

        resultBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, e);

        service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
    }

    /**
     * Attempt to deliver any outstanding messages we've received but which the
     * application hasn't acknowledged. If "cleanSession" was specified, we'll
     * have already purged any such messages from our messageStore.
     */
    private void deliverBacklog() {
        Iterator<StoredMessage> backlog = service.messageStore.getAllArrivedMessages(clientHandle);
        while (backlog.hasNext()) {
            StoredMessage msgArrived = backlog.next();
            Bundle resultBundle = messageToBundle(msgArrived.getMessageId(), msgArrived.getTopic(),
                    msgArrived.getMessage());
            resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION,
                    MqttServiceConstants.MESSAGE_ARRIVED_ACTION);
            service.callbackToActivity(clientHandle, Status.OK, resultBundle);
        }
    }

    /**
     * Create a bundle containing all relevant data pertaining to a message
     *
     * @param messageId
     *            the message's identifier in the messageStore, so that a
     *            callback can be made to remove it once delivered
     * @param topic
     *            the topic on which the message was delivered
     * @param message
     *            the message itself
     * @return the bundle
     */
    private Bundle messageToBundle(String messageId, String topic, MqttMessage message) {
        Bundle result = new Bundle();
        result.putString(MqttServiceConstants.CALLBACK_MESSAGE_ID, messageId);
        result.putString(MqttServiceConstants.CALLBACK_DESTINATION_NAME, topic);
        result.putParcelable(MqttServiceConstants.CALLBACK_MESSAGE_PARCEL, new ParcelableMqttMessage(message));
        return result;
    }

    /**
     * Close connection from the server
     *
     */
    void close() {
        Log.v("mqtt", "MqttConnection close()");
        service.traceDebug(TAG, "close()");
        try {
            if (myClient != null) {
                myClient.close();
            }
        } catch (MqttException e) {
            // Pass a new bundle, let handleException stores error messages.
            handleException(new Bundle(), e);
        }
    }

    /**
     * Disconnect from the server
     *
     * @param quiesceTimeout
     *            in milliseconds
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary string to be passed back to the activity
     */
    void disconnect(long quiesceTimeout, String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection disconnect()");
        service.traceDebug(TAG, "disconnect()");
        disconnected = true;
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.DISCONNECT_ACTION);
        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                myClient.disconnect(quiesceTimeout, invocationContext, listener);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);
            service.traceError(MqttServiceConstants.DISCONNECT_ACTION, NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }

        if (connectOptions.isCleanSession()) {
            // assume we'll clear the stored messages at this point
            service.messageStore.clearArrivedMessages(clientHandle);
        }

        releaseWakeLock();
    }

    /**
     * Disconnect from the server
     *
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary string to be passed back to the activity
     */
    void disconnect(String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection disconnect() 2");
        service.traceDebug(TAG, "disconnect()");
        disconnected = true;
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.DISCONNECT_ACTION);
        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                myClient.disconnect(invocationContext, listener);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);
            service.traceError(MqttServiceConstants.DISCONNECT_ACTION, NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }

        if (connectOptions.isCleanSession()) {
            // assume we'll clear the stored messages at this point
            service.messageStore.clearArrivedMessages(clientHandle);
        }
        releaseWakeLock();
    }

    /**
     * @return true if we are connected to an MQTT server
     */
    public boolean isConnected() {
        Log.v("mqtt", "MqttConnection isConnected()");
        if (myClient != null)
            return myClient.isConnected();
        return false;
    }

    /**
     * Publish a message on a topic
     *
     * @param topic
     *            the topic on which to publish - represented as a string, not
     *            an MqttTopic object
     * @param payload
     *            the content of the message to publish
     * @param qos
     *            the quality of service requested
     * @param retained
     *            whether the MQTT server should retain this message
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary string to be passed back to the activity
     * @return token for tracking the operation
     */
    public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean retained,
            String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection publish");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.SEND_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);

        IMqttDeliveryToken sendToken = null;

        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                MqttMessage message = new MqttMessage(payload);
                message.setQos(qos);
                message.setRetained(retained);
                sendToken = myClient.publish(topic, payload, qos, retained, invocationContext, listener);
                storeSendDetails(topic, message, sendToken, invocationContext, activityToken);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);
            service.traceError(MqttServiceConstants.SEND_ACTION, NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }

        return sendToken;
    }

    /**
     * Publish a message on a topic
     *
     * @param topic
     *            the topic on which to publish - represented as a string, not
     *            an MqttTopic object
     * @param message
     *            the message to publish
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary string to be passed back to the activity
     * @return token for tracking the operation
     */
    public IMqttDeliveryToken publish(String topic, MqttMessage message, String invocationContext,
            String activityToken) {
        Log.v("mqtt", "MqttConnection publish 2");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.SEND_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);

        IMqttDeliveryToken sendToken = null;

        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                sendToken = myClient.publish(topic, message, invocationContext, listener);
                storeSendDetails(topic, message, sendToken, invocationContext, activityToken);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);
            service.traceError(MqttServiceConstants.SEND_ACTION, NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }
        return sendToken;
    }

    /**
     * Subscribe to a topic
     *
     * @param topic
     *            a possibly wildcarded topic name
     * @param qos
     *            requested quality of service for the topic
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary identifier to be passed back to the Activity
     */
    public void subscribe(final String topic, final int qos, String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection subscribe");
        service.traceDebug(TAG,
                "subscribe({" + topic + "}," + qos + ",{" + invocationContext + "}, {" + activityToken + "}");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.SUBSCRIBE_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);

        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                myClient.subscribe(topic, qos, invocationContext, listener);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);
            service.traceError("subscribe", NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }
    }

    /**
     * Subscribe to one or more topics
     *
     * @param topic
     *            a list of possibly wildcarded topic names
     * @param qos
     *            requested quality of service for each topic
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary identifier to be passed back to the Activity
     */
    public void subscribe(final String[] topic, final int[] qos, String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection subscribe 2");
        service.traceDebug(TAG,
                "subscribe({" + topic + "}," + qos + ",{" + invocationContext + "}, {" + activityToken + "}");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.SUBSCRIBE_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);

        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                myClient.subscribe(topic, qos, invocationContext, listener);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);
            service.traceError("subscribe", NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }
    }

    /**
     * Unsubscribe from a topic
     *
     * @param topic
     *            a possibly wildcarded topic name
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary identifier to be passed back to the Activity
     */
    void unsubscribe(final String topic, String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection unsubscribe");
        service.traceDebug(TAG,
                "unsubscribe({" + topic + "},{" + invocationContext + "}, {" + activityToken + "})");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.UNSUBSCRIBE_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);
        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                myClient.unsubscribe(topic, invocationContext, listener);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);

            service.traceError("subscribe", NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }
    }

    /**
     * Unsubscribe from one or more topics
     *
     * @param topic
     *            a list of possibly wildcarded topic names
     * @param invocationContext
     *            arbitrary data to be passed back to the application
     * @param activityToken
     *            arbitrary identifier to be passed back to the Activity
     */
    void unsubscribe(final String[] topic, String invocationContext, String activityToken) {
        Log.v("mqtt", "MqttConnection unsubscribe 2");
        service.traceDebug(TAG,
                "unsubscribe({" + topic + "},{" + invocationContext + "}, {" + activityToken + "})");
        final Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.UNSUBSCRIBE_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
        resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);
        if ((myClient != null) && (myClient.isConnected())) {
            IMqttActionListener listener = new MqttConnectionListener(resultBundle);
            try {
                myClient.unsubscribe(topic, invocationContext, listener);
            } catch (Exception e) {
                handleException(resultBundle, e);
            }
        } else {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, NOT_CONNECTED);

            service.traceError("subscribe", NOT_CONNECTED);
            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }
    }

    /**
     * Get tokens for all outstanding deliveries for a client
     *
     * @return an array (possibly empty) of tokens
     */
    public IMqttDeliveryToken[] getPendingDeliveryTokens() {
        Log.v("mqtt", "MqttConnection getPendingDeliveryTokens()");
        return myClient.getPendingDeliveryTokens();
    }

    // Implement MqttCallback

    /**
     * Callback for connectionLost
     *
     * @param why
     *            the exeception causing the break in communications
     */
    @Override
    public void connectionLost(Throwable why) {
        Log.v("mqtt", "MqttConnection connectionLost()");
        service.traceDebug(TAG, "connectionLost(" + why.getMessage() + ")");
        disconnected = true;
        try {
            myClient.disconnect(null, new IMqttActionListener() {

                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    // No action
                    Log.v("mqtt", "MqttConnection connectionLost() disconnect onSuccess");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    // No action
                    Log.v("mqtt", "MqttConnection connectionLost() disconnect onFailure");
                }
            });
        } catch (Exception e) {
            // ignore it - we've done our best
        }

        Bundle resultBundle = new Bundle();
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION,
                MqttServiceConstants.ON_CONNECTION_LOST_ACTION);
        if (why != null) {
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, why.getMessage());
            if (why instanceof MqttException) {
                resultBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, why);
            }
            resultBundle.putString(MqttServiceConstants.CALLBACK_EXCEPTION_STACK, Log.getStackTraceString(why));
        }
        service.callbackToActivity(clientHandle, Status.OK, resultBundle);
        // client has lost connection no need for wake lock
        releaseWakeLock();
    }

    /**
     * Callback to indicate a message has been delivered (the exact meaning of
     * "has been delivered" is dependent on the QOS value)
     *
     * @param messageToken
     *            the messge token provided when the message was originally sent
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken messageToken) {
        Log.v("mqtt", "MqttConnection deliveryComplete()");
        service.traceDebug(TAG, "deliveryComplete(" + messageToken + ")");

        MqttMessage message = savedSentMessages.remove(messageToken);
        if (message != null) { // If I don't know about the message, it's
            // irrelevant
            String topic = savedTopics.remove(messageToken);
            String activityToken = savedActivityTokens.remove(messageToken);
            String invocationContext = savedInvocationContexts.remove(messageToken);

            Bundle resultBundle = messageToBundle(null, topic, message);
            if (activityToken != null) {
                resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.SEND_ACTION);
                resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, activityToken);
                resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, invocationContext);

                service.callbackToActivity(clientHandle, Status.OK, resultBundle);
            }
            resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION,
                    MqttServiceConstants.MESSAGE_DELIVERED_ACTION);
            service.callbackToActivity(clientHandle, Status.OK, resultBundle);
        }

        // this notification will have kept the connection alive but send the previously sechudled ping anyway
    }

    /**
     * Callback when a message is received
     *
     * @param topic
     *            the topic on which the message was received
     * @param message
     *            the message itself
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        Log.v("mqtt", "MqttConnection messageArrived()");
        service.traceDebug(TAG, "messageArrived(" + topic + ",{" + message.toString() + "})");

        String messageId = service.messageStore.storeArrived(clientHandle, topic, message);

        parseMqttMessageV2(topic, message);

        Bundle resultBundle = messageToBundle(messageId, topic, message);
        resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.MESSAGE_ARRIVED_ACTION);
        resultBundle.putString(MqttServiceConstants.CALLBACK_MESSAGE_ID, messageId);
        service.callbackToActivity(clientHandle, Status.OK, resultBundle);

    }

    private void parseMqttMessageV2(String topic, MqttMessage mqttMessage) throws Exception {
        Log.v("mqtt", "parseMqttMessageV2");
        Context ctx = NanuService.getContext();
        byte origMqttMsgByte[] = mqttMessage.getPayload();
        int mqttIndex = 0;
        boolean processVTagSuccess = false;

        boolean processPTagSuccess = false;
        long mqttPacketValue = 0;

        boolean processTTagSuccess = false;
        long mqttTimestampValue = 0;

        boolean processLTagSuccess = false;
        int mqttMsgLengthValue = 0;

        boolean processMTagSuccess = false;
        String mqttMessageValue = "";
        String mqttMembersValue = "";

        boolean processGTagSuccess = false;
        long mqttGroupIDValue = 0;

        boolean processSTagSuccess = false;
        String mqttSubjectValue = "";

        boolean processCTagSuccess = false;
        int mqttMemberCountValue = 0;

        boolean processNTagSuccess = false;
        int mqttAdminCountValue = 0;

        boolean processATagSuccess = false;
        String mqttAdminsValue = "";

        String[] topicArray = topic.split("\\/");

        String sender = topicArray[2];
        if (topicArray.length == 4) {
            processGTagSuccess = true;
            try {
                mqttGroupIDValue = Long.parseLong(topicArray[3].toString().trim());
            } catch (NumberFormatException nfe) {
                processGTagSuccess = false;
                nfe.printStackTrace();
            }

            if (mqttGroupIDValue == 0) {
                try {
                    mqttGroupIDValue = Long.valueOf(topicArray[3].trim());
                } catch (Exception err) {
                    processGTagSuccess = false;
                    err.printStackTrace();
                }
            }
        }

        String mqttMsgDateValue = "";
        for (int indexMqttCounter = 0; indexMqttCounter < origMqttMsgByte.length; indexMqttCounter++) {
            /*       Log.v(SettingsManager.TAG, "MqttService origMqttMsgByte[" + indexMqttCounter + "] = " + origMqttMsgByte[indexMqttCounter]); */
        }

        for (int indexMqttCounter = 0; indexMqttCounter < origMqttMsgByte.length; indexMqttCounter++) {
            if (indexMqttCounter == 0) {
                mqttIndex = indexMqttCounter;
                long mqttVTag = getMqttTag(origMqttMsgByte, mqttIndex);
                if (mqttVTag != -1) {
                    if (mqttVTag == 86) // "V"
                    {
                        processVTagSuccess = true;
                        mqttIndex = mqttIndex + 2;
                    } else {
                        processVTagSuccess = false;
                        break;
                    }
                }
            } else {
                if (mqttIndex == indexMqttCounter) {
                    long mqttTag = getMqttTag(origMqttMsgByte, mqttIndex);
                    if (mqttTag != -1) {
                        if (mqttTag == 80) /* "P" */ {
                            mqttIndex = mqttIndex + 1;
                            long mPValue = origMqttMsgByte[mqttIndex];
                            mqttPacketValue = mPValue;
                            mqttIndex = mqttIndex + 1;
                            processPTagSuccess = true;
                        } else if (mqttTag == 84) /* "T" */ {
                            mqttIndex = mqttIndex + 1;
                            byte timeStampArray[] = new byte[8];
                            for (int i = 0; i < 8; i++) {
                                timeStampArray[i] = origMqttMsgByte[mqttIndex + i];
                            }
                            mqttTimestampValue = ByteBuffer.wrap(timeStampArray).order(ByteOrder.LITTLE_ENDIAN)
                                    .getLong();

                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
                            String messageYear = sdf.format(mqttTimestampValue);
                            if (messageYear.length() != 4) {
                                mqttTimestampValue = ByteBuffer.wrap(timeStampArray).order(ByteOrder.BIG_ENDIAN)
                                        .getLong();
                            }
                            SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            String messageDate = sdfDate.format(mqttTimestampValue);
                            processTTagSuccess = true;
                            mqttIndex = mqttIndex + 8;
                        } else if (mqttTag == 76) /* "L" */ {
                            if (processPTagSuccess) {
                                if (mqttPacketValue == -128 || (mqttPacketValue == -117)
                                        || (mqttPacketValue == -115) || (mqttPacketValue == -126)) {
                                    mqttIndex = mqttIndex + 1;
                                    mqttMsgLengthValue = origMqttMsgByte[mqttIndex];
                                    processLTagSuccess = true;
                                    mqttIndex = mqttIndex + 1;
                                } else if (mqttPacketValue == 0) {
                                    mqttIndex = mqttIndex + 1;
                                    byte msgLengthArray[] = new byte[4];
                                    for (int i = 0; i < 4; i++) {
                                        msgLengthArray[i] = origMqttMsgByte[mqttIndex + i];
                                    }
                                    mqttMsgLengthValue = ByteBuffer.wrap(msgLengthArray)
                                            .order(ByteOrder.LITTLE_ENDIAN).getInt();
                                    processLTagSuccess = true;
                                    mqttIndex = mqttIndex + 4;
                                }
                            }
                        } else if (mqttTag == 77) /* "M" */ {
                            if (processPTagSuccess) {
                                if ((mqttPacketValue == -128) || (mqttPacketValue == -124)
                                        || (mqttPacketValue == -126) || (mqttPacketValue == -117)) {

                                    if (processCTagSuccess) {
                                        mqttIndex = mqttIndex + 1;
                                        for (int i = 0; i < mqttMemberCountValue; i++) {
                                            byte groupMembersArray[] = new byte[8];
                                            for (int j = 0; j < 8; j++) {
                                                groupMembersArray[j] = origMqttMsgByte[mqttIndex + j];
                                            }
                                            long participants = ByteBuffer.wrap(groupMembersArray)
                                                    .order(ByteOrder.LITTLE_ENDIAN).getLong();
                                            mqttIndex = mqttIndex + 8;
                                            if (i == (mqttMemberCountValue - 1)) {
                                                mqttMembersValue = mqttMembersValue + participants;
                                            } else {
                                                mqttMembersValue = mqttMembersValue + participants + ",";
                                            }
                                        }
                                        processMTagSuccess = true;
                                    } else {
                                        break;
                                    }
                                } else if (mqttPacketValue == 0) {
                                    if (processLTagSuccess) {
                                        mqttIndex = mqttIndex + 1;
                                        if (mqttMsgLengthValue > 0) {
                                            byte messageArray[] = null;
                                            try {
                                                messageArray = new byte[mqttMsgLengthValue];
                                            } catch (Exception err) {
                                                err.printStackTrace();
                                                processMTagSuccess = false;
                                                break;
                                            }

                                            for (int i = 0; i < mqttMsgLengthValue; i++) {
                                                messageArray[i] = origMqttMsgByte[mqttIndex + i];
                                            }
                                            mqttMessageValue = new String(messageArray);
                                            processMTagSuccess = true;
                                            mqttIndex = mqttIndex + mqttMsgLengthValue + 1;
                                        }
                                    } else {
                                        break;
                                    }
                                }
                            }
                        } else if (mqttTag == 71) /* "G" */ {
                            mqttIndex = mqttIndex + 1;
                            byte groupIDArray[] = new byte[8];
                            for (int i = 0; i < 8; i++) {
                                groupIDArray[i] = origMqttMsgByte[mqttIndex + i];
                            }
                            mqttGroupIDValue = ByteBuffer.wrap(groupIDArray).order(ByteOrder.LITTLE_ENDIAN)
                                    .getLong();
                            processGTagSuccess = true;
                            mqttIndex = mqttIndex + 8;
                        } else if (mqttTag == 83) /* "S" */ {
                            if (processLTagSuccess) {
                                mqttIndex = mqttIndex + 1;
                                if (mqttMsgLengthValue > 0) {
                                    byte subjectArray[] = null;
                                    try {
                                        subjectArray = new byte[mqttMsgLengthValue];
                                    } catch (Exception err) {
                                        err.printStackTrace();
                                        processSTagSuccess = false;
                                        break;
                                    }
                                    for (int i = 0; i < mqttMsgLengthValue; i++) {
                                        subjectArray[i] = origMqttMsgByte[mqttIndex + i];
                                    }
                                    mqttSubjectValue = new String(subjectArray);
                                    processSTagSuccess = true;
                                    mqttIndex = mqttIndex + mqttMsgLengthValue;
                                }
                            } else {
                                break;
                            }
                        } else if (mqttTag == 67) /* "C" */ {
                            mqttIndex = mqttIndex + 1;
                            mqttMemberCountValue = origMqttMsgByte[mqttIndex];
                            processCTagSuccess = true;
                            mqttIndex = mqttIndex + 1;
                        } else if (mqttTag == 78) /* "N" */ {
                            mqttIndex = mqttIndex + 1;
                            mqttAdminCountValue = origMqttMsgByte[mqttIndex];
                            processNTagSuccess = true;
                            mqttIndex = mqttIndex + 1;
                        } else if (mqttTag == 65) /* "A" */ {
                            if (processPTagSuccess) {
                                if (mqttPacketValue == -117) {
                                    if (processNTagSuccess) {
                                        mqttIndex = mqttIndex + 1;
                                        for (int i = 0; i < mqttAdminCountValue; i++) {
                                            byte groupAdminsArray[] = new byte[8];
                                            for (int j = 0; j < 8; j++) {
                                                groupAdminsArray[j] = origMqttMsgByte[mqttIndex + j];
                                            }
                                            long admins = ByteBuffer.wrap(groupAdminsArray)
                                                    .order(ByteOrder.LITTLE_ENDIAN).getLong();
                                            mqttIndex = mqttIndex + 8;
                                            if (i == (mqttAdminCountValue - 1)) {
                                                mqttAdminsValue = mqttAdminsValue + admins;
                                            } else {
                                                mqttAdminsValue = mqttAdminsValue + admins + ",";
                                            }
                                        }
                                        processATagSuccess = true;
                                    } else {
                                        break;
                                    }
                                }
                            }
                        } else {
                            break;
                        }
                    } else {
                        break;
                    }
                }
            }
        }

        if (!processVTagSuccess) {
            return;
        }

        PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
        boolean isScreenOn = pm.isScreenOn();
        if (isScreenOn == false) {
            WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
                    | PowerManager.ON_AFTER_RELEASE, "MyLock");
            if (wl.isHeld()) {
                wl.release();
            }
            wl.acquire(10000);
            WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyCpuLock");
            if (wl_cpu.isHeld()) {
                wl_cpu.release();
            }
            wl_cpu.acquire(10000);
        }

        String message = mqttMessageValue;
        Log.v("mqtt", "from: " + sender);
        Log.v("mqtt", "message: " + message);
        Intent intent = new Intent();
        intent.setClassName(ctx, "org.eclipse.paho.android.service.sample.MainActivity");
        intent.putExtra("handle", clientHandle);
        String ns = Context.NOTIFICATION_SERVICE;
        NotificationManager mNotificationManager = (NotificationManager) ctx.getSystemService(ns);
        int messageNotificationId = 1;
        mNotificationManager.cancel(messageNotificationId);
        Calendar.getInstance().getTime().toString();
        long when = System.currentTimeMillis();
        String ticker = sender + " " + mqttMessageValue;
        PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 3, intent, 0);
        NotificationCompat.Builder notificationCompat = new NotificationCompat.Builder(ctx);
        notificationCompat.setAutoCancel(true).setContentTitle(sender).setContentIntent(pendingIntent)
                .setContentText(mqttMessageValue).setTicker(ticker).setWhen(when)
                .setSmallIcon(R.drawable.ic_launcher);

        //  Notification notification = notificationCompat.build();
        Bitmap iconLarge = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.ic_launcher);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctx)
                .setSmallIcon(R.drawable.ic_launcher).setLargeIcon(iconLarge).setContentTitle(sender)
                .setContentText(mqttMessageValue);

        mBuilder.setContentIntent(pendingIntent);
        mBuilder.setTicker(message);
        mBuilder.setAutoCancel(true);
        mBuilder.setDefaults(
                Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
        mNotificationManager.notify(messageNotificationId, mBuilder.build());
    }

    private long getMqttTag(byte mqttMsgByte[], int mqttIndexTagCounter) {
        try {
            long mTag = mqttMsgByte[mqttIndexTagCounter];
            return mTag;
        } catch (Exception err) {
            err.printStackTrace();
        }
        return -1;
    }

    /**
     * Store details of sent messages so we can handle "deliveryComplete"
     * callbacks from the mqttClient
     *
     * @param topic
     * @param msg
     * @param messageToken
     * @param invocationContext
     * @param activityToken
     */
    private void storeSendDetails(final String topic, final MqttMessage msg, final IMqttDeliveryToken messageToken,
            final String invocationContext, final String activityToken) {
        savedTopics.put(messageToken, topic);
        savedSentMessages.put(messageToken, msg);
        savedActivityTokens.put(messageToken, activityToken);
        savedInvocationContexts.put(messageToken, invocationContext);
    }

    /**
     * Acquires a partial wake lock for this client
     */
    private void acquireWakeLock() {
        if (wakelock == null) {
            PowerManager pm = (PowerManager) service.getSystemService(Service.POWER_SERVICE);
            wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
        }
        wakelock.acquire();

    }

    /**
     * Releases the currently held wake lock for this client
     */
    private void releaseWakeLock() {
        if (wakelock != null && wakelock.isHeld()) {
            wakelock.release();
        }
    }

    /**
     * General-purpose IMqttActionListener for the Client context
     * <p>
     * Simply handles the basic success/failure cases for operations which don't
     * return results
     *
     */
    private class MqttConnectionListener implements IMqttActionListener {

        private final Bundle resultBundle;

        private MqttConnectionListener(Bundle resultBundle) {
            this.resultBundle = resultBundle;
        }

        @Override
        public void onSuccess(IMqttToken asyncActionToken) {
            Log.v("mqtt", "MqttConnection MqttConnectionListener onSuccess");
            service.callbackToActivity(clientHandle, Status.OK, resultBundle);
        }

        @Override
        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
            Log.v("mqtt", "MqttConnection MqttConnectionListener onFailure");
            resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, exception.getLocalizedMessage());

            resultBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, exception);

            service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);
        }
    }

    /**
     * Receive notification that we are offline<br>
     * if cleanSession is true, we need to regard this as a disconnection
     */
    void offline() {
        Log.v("mqtt", "MqttConnection offline()");
        if (!disconnected && !cleanSession) {
            Exception e = new Exception("Android offline");
            connectionLost(e);
        }
    }

    /**
     * Reconnect<br>
     * Only appropriate if cleanSession is false and we were connected.
     * Declare as synchronized to avoid multiple calls to this method to send connect
     * multiple times
     */
    synchronized void reconnect() {
        Log.v("mqtt", "MqttConnection reconnect()");
        if (isConnecting) {
            Log.v("mqtt", "MqttConnection reconnect() The client is connecting. Reconnect return directly.");
            service.traceDebug(TAG, "The client is connecting. Reconnect return directly.");
            return;
        }

        if (!service.isOnline()) {
            Log.v("mqtt", "The network is not reachable. Will not do reconnect");
            service.traceDebug(TAG, "The network is not reachable. Will not do reconnect");
            return;
        }

        if (disconnected && !cleanSession) {
            Log.v("mqtt", "Do Real Reconnect!");
            // use the activityToke the same with action connect
            service.traceDebug(TAG, "Do Real Reconnect!");
            final Bundle resultBundle = new Bundle();
            resultBundle.putString(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN, reconnectActivityToken);
            resultBundle.putString(MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT, null);
            resultBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.CONNECT_ACTION);

            try {

                IMqttActionListener listener = new MqttConnectionListener(resultBundle) {
                    @Override
                    public void onSuccess(IMqttToken asyncActionToken) {
                        // since the device's cpu can go to sleep, acquire a
                        // wakelock and drop it later.
                        service.traceDebug(TAG, "Reconnect Success!");
                        service.traceDebug(TAG, "DeliverBacklog when reconnect.");
                        doAfterConnectSuccess(resultBundle);
                    }

                    @Override
                    public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                        resultBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE,
                                exception.getLocalizedMessage());
                        resultBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, exception);
                        service.callbackToActivity(clientHandle, Status.ERROR, resultBundle);

                        doAfterConnectFail(resultBundle);

                    }
                };

                myClient.connect(connectOptions, null, listener);
                setConnectingState(true);
            } catch (MqttException e) {
                service.traceError(TAG, "Cannot reconnect to remote server." + e.getMessage());
                setConnectingState(false);
                handleException(resultBundle, e);
            }
        }
    }

    /**
     *
     * @param isConnecting
     */
    synchronized void setConnectingState(boolean isConnecting) {
        Log.v("mqtt", "MqttConnection setConnectingState");
        this.isConnecting = isConnecting;
    }

}