pubsub.io.android.Pubsub.java Source code

Java tutorial

Introduction

Here is the source code for pubsub.io.android.Pubsub.java

Source

/*
 * pubsub.io Android Library
 * Copyright (C) 2011  Andreas Gransson
    
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
    
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
    
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package pubsub.io.android;

import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

/**
 * Pubsub.io Android service class. This class allows an Android app to send to,
 * and read from, pubsub.io subs.
 * 
 * The reason for having this as a service instead of a component of an app is
 * if the library should be used in a passive sense as well as active we need to
 * be able of reading the connection while the application is not in the
 * foreground.
 * 
 * @author Andreas Goransson
 * 
 */
public class Pubsub {

    private static final String TAG = "Pubsub";
    private boolean DEBUG = false;

    // Callback constants
    /** Recieved raw bytes from the socket */
    public static final int RAW_TEXT = 10;

    /** Perform all subscribes in this callback! */
    public static final int SUBSCRIBES = 12;

    /** Connection changed state */
    public static final int STATE_CHANGE = 13;

    /** Notification that the connection was lost (was connected) */
    public static final int CONNECTION_LOST = 14;

    /** Notification that the connection failed (was never connected) */
    public static final int CONNECTION_FAILED = 16;

    /** Recieved when succesful connection was established to PubSub host */
    public static final int CONNECTED_TO_HOST = 15;
    public static final String HOST_NAME = "host";

    /** Message sent by this client to PubSub.io host */
    public static final int SENT_MESSAGE = 16;

    private PubsubComm mPubsubComm = null;
    private Handler mHandler;

    private String mHost = "";
    private String mPort = "";
    private String mSub = "";

    private Context mContext;

    public Pubsub(Context ctx, Handler handler) {
        mContext = ctx;
        mHandler = handler;

        setupPubsub();
    }

    /**
     * To debug or not debug, it is the question.
     * 
     * @param debug
     *            ...and this is the answer.
     */
    public void DEBUG(boolean debug) {
        this.DEBUG = debug;
    }

    private void setupPubsub() {
        if (DEBUG)
            Log.i(TAG, "setupPubsub()");

        // Initialize the BluetoothChatService to perform bluetooth connections
        mPubsubComm = new PubsubComm(mContext, mHandler);
    }

    /**
     * Connect to the default sub at hub.pubsub.io.
     */
    public void connect() {
        // connect("hub.pubsub.io", "10547", "/");
        connect("79.125.4.43", "10547", "/");
    }

    /**
     * Connect to a specified sub at hub.pubsub.io.
     * 
     * @param sub
     */
    public void connect(String sub) {
        // connect("hub.pubsub.io", "10547", sub);
        connect("79.125.4.43", "10547", sub);
    }

    /**
     * Connect to a specified sub on a specified pubsub hub.
     * 
     * @param url
     * @param port
     */
    public void connect(String host, String port, String sub) {
        if (DEBUG)
            Log.i(TAG, "connect(" + host + ", " + port + ", " + sub + ")");

        if (!hasInternet()) {
            Toast.makeText(mContext, "Your device needs internet connection! Connection aborted!",
                    Toast.LENGTH_SHORT).show();
            return;
        }

        mHost = host;
        mPort = port;
        mSub = sub;

        mPubsubComm.connect(mHost, mPort, mSub);
    }

    public void reconnect() {
        if (mHost != null && mPort != null && mSub != null)
            this.connect(mHost, mPort, mSub);
    }

    /**
     * Hook up to a specific sub.
     * 
     * @param sub
     */
    public void sub(String sub) {
        if (DEBUG)
            Log.i(TAG, "Sub: " + sub);

        // Check that we're actually connected before trying anything
        if (mPubsubComm.getState() != mPubsubComm.STATE_CONNECTED) {
            Toast.makeText(mContext, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            mPubsubComm.write(PubsubParser.sub(sub).getBytes());
        } catch (JSONException e) {
            Log.e(TAG, e.getMessage(), e);
        }
    }

    /**
     * Subscribe to a filter, with a specified handler_callback, on the
     * connected sub. The handler_callback should be a declared constant, and it
     * should be used in the Handler of your activity!
     * 
     * @param json_filter
     * @param handler_callback
     * @throws JSONException
     */
    public void subscribe(JSONObject json_filter, int handler_callback) throws JSONException {
        if (DEBUG)
            Log.i(TAG, "Subscribe: " + json_filter.toString());

        // Check that we're actually connected before trying anything
        if (mPubsubComm.getState() != mPubsubComm.STATE_CONNECTED) {
            Toast.makeText(mContext, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        new CommTask().execute(PubsubParser.subscribe(json_filter, handler_callback).getBytes());
    }

    /**
     * Unsubscribe the specified handler_callback.
     * 
     * @param handler_callback
     * @throws JSONException
     */
    public void unsubscribe(Integer handler_callback) throws JSONException {
        if (DEBUG)
            Log.i(TAG, "Unsubscribe: " + handler_callback);

        // Check that we're actually connected before trying anything
        if (mPubsubComm.getState() != mPubsubComm.STATE_CONNECTED) {
            Toast.makeText(mContext, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        new CommTask().execute(PubsubParser.unsubscribe(handler_callback).getBytes());
    }

    /**
     * Publish a document to the connected sub.
     * 
     * @param doc
     * @throws JSONException
     */
    public void publish(JSONObject doc) throws JSONException {
        if (DEBUG)
            Log.i(TAG, "Publish: " + doc.toString());

        // Check that we're actually connected before trying anything
        if (mPubsubComm.getState() != mPubsubComm.STATE_CONNECTED) {
            Toast.makeText(mContext, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        new CommTask().execute(PubsubParser.publish(doc).getBytes());
    }

    /**
     * Disconnect the communication, this will stop the thread (and consequently
     * all socket communication too)
     */
    public void disconnect() {
        if (DEBUG)
            Log.i(TAG, "disconnect()");

        if (mPubsubComm != null)
            mPubsubComm.stop();
    }

    /**
     * Set the callback handler for the service. This is the handler where all
     * callbacks from the hub will arrive, and also some library callbacks can
     * be read from the same handler. Library handlers include RAW_TEXT,
     * TERMINATED, and ERROR.
     * 
     * @param handler
     */
    public void setHandler(Handler handler) {
        if (DEBUG)
            Log.i(TAG, "setHandler()");

        mHandler = handler;
    }

    /**
     * Basic write. For the love of god, don't use this!!! All hell will break
     * loose and tiny ants will eat your skin off when you sleep!
     * 
     * Nah, it's not that bad... chances are you'll do it wrong though so it
     * won't work.
     * 
     * @param message
     */
    @Deprecated
    protected void write(String message) {
        if (DEBUG)
            Log.i(TAG, "Write: " + message);

        // Check that we're actually connected before trying anything
        if (mPubsubComm.getState() != mPubsubComm.STATE_CONNECTED) {
            Toast.makeText(mContext, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        // Send a message to the PubSub.io host
        mPubsubComm.write(message.getBytes());
    }

    /**
     * Detects if we have internet or not, checks both WiFi and 3G.
     * 
     * @return
     */
    public boolean hasInternet() {
        if (DEBUG)
            Log.i(TAG, "hasInternet()");

        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);

        if (DEBUG)
            Log.i(TAG, "Testing WiFi status");

        // First test wifi for status!
        NetworkInfo netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        if (netInfo != null && netInfo.isConnectedOrConnecting()) {
            if (DEBUG)
                Log.i(TAG, "WiFi detected, connecting");
            return true;
        }

        if (DEBUG)
            Log.i(TAG, "No WiFi detected, trying mobile");

        netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        if (netInfo != null && netInfo.isConnectedOrConnecting()) {
            if (DEBUG)
                Log.i(TAG, "Mobile detected, connecting");
            return true;
        }

        if (DEBUG)
            Log.i(TAG, "No Mobile detected, aborting");

        return false;
    }

    @SuppressLint("NewApi")
    private class CommTask extends AsyncTask<byte[], Void, Void> {

        @Override
        protected Void doInBackground(byte[]... params) {
            mPubsubComm.write(params[0]);
            return null;
        }
    }

}