se.mah.k3.goransson.andreas.essemmesslib.Essemmess.java Source code

Java tutorial

Introduction

Here is the source code for se.mah.k3.goransson.andreas.essemmesslib.Essemmess.java

Source

package se.mah.k3.goransson.andreas.essemmesslib;

/*
 * Essemmess.java
 * 
 * Connects to, and interacts with, the messaging-system set up at 
 * Malm University. This library is part of the Android specific mobile 
 * design courses at Arts and Communication.
 * 
 * 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/>.
 */

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;

/**
 * Essemmess is a library used for communicating and interacting with the
 * message service developed at Malm University, and is used for educational
 * purposes at the programming courses at Arts and Communication.
 * 
 * @author Andreas Gransson, andreas.goransson@mah.se
 * 
 */
public class Essemmess {

    /* Application context */
    private Context ctx;

    /* Stored access_token, acquired from server */
    private String access_token;

    /* Connectivity manager - Internet connected? */
    private ConnectivityManager mConnectivityManager;

    /* Enable debugg messages */
    private boolean DEBUG = true;

    /**
     * Create a new Essemmess instance, pass the current foreground context
     * otherwise the app might crash. Do not use "getApplicationContext()" if
     * you can avoid it.
     * 
     * @param ctx
     */
    public Essemmess(Context ctx) {
        this.ctx = ctx;

        mConnectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    /**
     * Sets the current context of the Essemmess server, should be used if you
     * use the same server instance in multiple activies. Otherwise the
     * application will probably crash.
     * 
     * @param ctx
     */
    public void setContext(Context ctx) {
        this.ctx = ctx;
    }

    /**
     * Returns the md5 access_token stored inside the server.
     * 
     * @return
     */
    public String getToken() {
        return access_token;
    }

    public boolean isLoggedIn() {
        return (access_token.length() == 32 ? true : false);
    }

    /**
     * Registers a new user in the database.
     * 
     * @param username
     * @param password
     * @param email
     * @param avatar
     */
    public void register(String username, String password, String email, Bitmap avatar) {
        if (mConnectivityManager.getActiveNetworkInfo().isConnected()) {
            /* Make sure the avatar exists */
            if (avatar != null) {
                /* Get the image as string */
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                /* We want to keep a standard size for all avatars, 72x72px */
                getScaledBitmap(avatar, 72).compress(Bitmap.CompressFormat.JPEG, 75, stream);
                byte[] byte_arr = stream.toByteArray();
                String image_str = Base64.encodeToString(byte_arr, Base64.DEFAULT);

                /* Execute the HttpWorker as REGISTER with the parameters */
                new HttpWorker(this.ctx, HttpWorker.REGISTER).execute(username, password, email, image_str);
            } else {
                Toast.makeText(this.ctx, "Image capture failed, try again", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * Attempts to perform a login to the Essemmess server.
     * 
     * @param username
     * @param password
     */
    public void login(String username, String password) {
        if (mConnectivityManager.getActiveNetworkInfo().isConnectedOrConnecting()) {
            /* Execute the HttpWorker as LOGIN with the parameters */
            new HttpWorker(this.ctx, HttpWorker.LOGIN).execute(username, password);
        } else {
            /* Toast "not connected" */
            Toast.makeText(ctx, "No internet connection found when logging in to server.", Toast.LENGTH_SHORT)
                    .show();
        }
    }

    /**
     * Attemtps to perform a message publish to the Essemmess server.
     * 
     * @param message
     * @param tag
     */
    public void write(String message, String tag) {
        if (mConnectivityManager.getActiveNetworkInfo().isConnectedOrConnecting()) {
            /* Execute the HttpWorker as POST with the parameters */
            new HttpWorker(this.ctx, HttpWorker.WRITE).execute(access_token, message, tag);
        } else {
            /* Toast "not connected" */
            Toast.makeText(ctx, "No internet connection found when posting to server.", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * Unregisters the Essemmess server, this should be called when the
     * application is destroyed.
     */
    public void logout() {
        if (mConnectivityManager.getActiveNetworkInfo().isConnectedOrConnecting()) {
            /* Execute the HttpWorker as LOGOUT with the parameters */
            new HttpWorker(this.ctx, HttpWorker.LOGOUT).execute(access_token);
        } else {
            /* Toast "not connected" */
            Toast.makeText(ctx, "No internet connection found when logging out of server.", Toast.LENGTH_SHORT)
                    .show();
        }
    }

    /**
     * Attempts to read messages published on the Essemmess server.
     */
    public void read() {
        /* Just issue an empty read() request */
        read("");
    }

    /**
     * Attempts to read messages published on the Essemmess server.
     * 
     * @param filter_tag
     */
    public void read(String filter_tag) {
        if (mConnectivityManager.getActiveNetworkInfo().isConnectedOrConnecting()) {
            /* Execute the HttpWorker as READ with the parameters */
            new HttpWorker(this.ctx, HttpWorker.READ).execute(access_token, filter_tag);
        } else {
            /* Toast "not connected" */
            Toast.makeText(ctx, "No internet connection found when reading messages on server.", Toast.LENGTH_SHORT)
                    .show();
        }
    }

    /**
     * Resizes the bitmap to a smaller, squared, version.
     * 
     * @param bmp
     * @return
     */
    private Bitmap getScaledBitmap(Bitmap bmp, int size) {
        int width = bmp.getWidth();
        int height = bmp.getHeight();

        /* Get the scale */
        float scale_w = ((float) size) / width;
        float scale_h = ((float) size) / height;

        /* Transformation matrix */
        Matrix matrix = new Matrix();
        matrix.postScale(scale_w, scale_h);

        /* Get the new bitmap */
        Bitmap resized = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true);

        return resized;
    }

    /**
     * Generic Worker, used to connect to, and read responses from, the
     * Essemmess server.
     * 
     * @author Andreas Gransson, andreas.goransson@mah.se
     */
    private class HttpWorker extends AsyncTask<String, Void, String> {

        /* TAG */
        private static final String TAG = "HttpWorker";

        /* Location of the server scripts */
        private static final String SERVER = "http://195.178.232.26/essemmess/";

        /* Action constants */
        public static final int LOGIN = 10;
        public static final int WRITE = 11;
        public static final int READ = 12;
        public static final int LOGOUT = 13;
        public static final int REGISTER = 14;

        /* Selected action */
        private int action;

        /* The progress dialog, used while waiting for http POST */
        private ProgressDialog mProgressDialog;

        public HttpWorker(Context ctx, int action) {
            this.action = action;
        }

        @Override
        protected void onPreExecute() {
            if (action != LOGOUT) {
                /* Create the dialog... */
                mProgressDialog = new ProgressDialog(Essemmess.this.ctx);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                mProgressDialog.setMessage("Working...");
                mProgressDialog.setCancelable(false);

                /* Show the dialog */
                mProgressDialog.show();
            }
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... params) {

            /* Server url */
            String url = null;

            /* Http POST arguments */
            ArrayList<NameValuePair> arguments = new ArrayList<NameValuePair>();

            /* Construct the POST and arguments */
            switch (action) {
            case LOGIN:
                /* Set the server url */
                url = SERVER + "login.php";

                /* Add the arguments */
                arguments.add(new BasicNameValuePair("username", params[0]));
                arguments.add(new BasicNameValuePair("password", params[1]));
                break;
            case WRITE:
                /* Set the url */
                url = SERVER + "post.php";

                /* Parameters... */
                arguments.add(new BasicNameValuePair("access_token", params[0]));
                arguments.add(new BasicNameValuePair("message", params[1]));
                arguments.add(new BasicNameValuePair("tag", params[2]));
                break;
            case READ:
                /* Set url */
                url = SERVER + "read.php";

                /* Parameters */
                arguments.add(new BasicNameValuePair("access_token", params[0]));
                arguments.add(new BasicNameValuePair("filter_tag", params[1]));
                break;
            case LOGOUT:
                /* Set the url */
                url = SERVER + "logout.php";

                /* Parameters... */
                arguments.add(new BasicNameValuePair("access_token", params[0]));
                break;
            case REGISTER:
                /* Set the url */
                url = SERVER + "register.php";

                /* Parameters... */
                arguments.add(new BasicNameValuePair("username", params[0]));
                arguments.add(new BasicNameValuePair("password", params[1]));
                arguments.add(new BasicNameValuePair("email", params[2]));
                arguments.add(new BasicNameValuePair("avatar", params[3]));
                break;
            }

            /* Fire the http post and store the response */
            return httppost(url, arguments);
        }

        @Override
        protected void onPostExecute(String response) {
            if (DEBUG)
                Log.i(TAG, (response != null ? response : "The server response was null, do you have internet?"));

            /* Make sure the http response has some content */
            if (response != null || response.length() > 0) {

                Log.i(TAG, "response Ok, kr post exec med action: " + action);

                /* Parse the JSON msg */
                try {
                    JSONObject json_data = new JSONObject(response);

                    /* Get the json message */
                    String message = json_data.getString("message");

                    /* We load the message body elsewhere because it changes */
                    String data;

                    switch (action) {
                    case LOGIN:
                        /* Store the access_token for future use */
                        access_token = json_data.getString("access_token");

                        /* Get the result */
                        data = json_data.getString("data");

                        /* Dispatch the login event */
                        dispatchEssemmessEvent(
                                new EssemmessLoginEvent(Essemmess.this, message, Boolean.parseBoolean(data)));

                        break;
                    case LOGOUT:
                        /* Just reset the access_token */
                        access_token = "";

                        /* Dispatch the logout event (there's no data in it...) */
                        dispatchEssemmessEvent(new EssemmessLogoutEvent(Essemmess.this, message));
                        break;
                    case WRITE:
                        /* Get the result */
                        data = json_data.getString("data");

                        /* Dispatch the write event */
                        if (Boolean.parseBoolean(data))
                            dispatchEssemmessEvent(new EssemmessWriteEvent(Essemmess.this, message, true));
                        else
                            dispatchEssemmessEvent(new EssemmessWriteEvent(Essemmess.this, message, false));

                        break;
                    case READ:
                        /* Read all posts from response into arraylist */
                        ArrayList<Post> posts = new ArrayList<Post>();

                        /* First test if the read failed! */
                        // The issue here is that this WILL return false if the
                        // data was OK...this needs to be fixed!
                        if (!Boolean.parseBoolean(json_data.getString("data"))) {
                            /* Dispatch the event with arraylist */
                            // dispatchEssemmessEvent(new
                            // EssemmessReadEvent(Essemmess.this,
                            // message, posts));
                            // break;
                        }

                        JSONArray json_array = json_data.getJSONArray("data");
                        for (int i = 0; i < json_array.length(); ++i) {
                            JSONObject json_post = json_array.getJSONObject(i);

                            JSONObject json_user = json_post.getJSONObject("user");
                            /* Decode the bitmap */
                            byte[] raw_image = Base64.decode(json_user.getString("avatar"), Base64.DEFAULT);
                            Bitmap avatar = BitmapFactory.decodeByteArray(raw_image, 0, raw_image.length);

                            /* Create the user */
                            User u = new User(json_user.getString("username"), json_user.getString("email"),
                                    avatar);

                            /* Add the post to the list */
                            posts.add(new Post(json_post.getString("tag"), u, json_post.getString("message"),
                                    json_post.getString("time")));
                        }

                        Log.i("test", "post size, inside lib: " + posts.size());

                        /* Dispatch the event with arraylist */
                        dispatchEssemmessEvent(new EssemmessReadEvent(Essemmess.this, message, posts));
                        break;
                    case REGISTER:
                        /* Get the result */
                        data = json_data.getString("data");

                        /* Dispatch the register event */
                        if (Boolean.parseBoolean(data)) {
                            dispatchEssemmessEvent(new EssemmessRegisterEvent(Essemmess.this, message, true));
                        } else {
                            dispatchEssemmessEvent(new EssemmessRegisterEvent(Essemmess.this, message, false));
                        }
                        break;
                    }

                } catch (JSONException e) {
                    Log.e(TAG, "Error parsing data " + e.toString());
                }

                /* We're done, shut the progress dialog off */
                if (mProgressDialog != null)
                    mProgressDialog.dismiss();

            } else {
                /* HTTP Post failed... */
                Toast.makeText(ctx, "Connection to server failed, please try again.", Toast.LENGTH_SHORT).show();

            }

            super.onPostExecute(response);
        }

        /**
         * Executes a httppost to a server instance with the given POST
         * arguments and returns a String response from the server.
         */
        private String httppost(String url, ArrayList<NameValuePair> args) {
            InputStream is = null;
            /* Send to server */
            try {
                /* Create the POST */
                HttpClient httpclient = new DefaultHttpClient();
                HttpPost httppost = new HttpPost(url);

                /* Add the "POST" variables in the php */
                httppost.setEntity(new UrlEncodedFormEntity(args));

                /* Execute the http POST and get the response */
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();
                is = entity.getContent();
            } catch (Exception e) {
                Log.e(TAG, "Error in http connection " + e.toString());
            }

            /* Read from server */
            try {
                /* Read the response stream */
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);

                /* Copy the response to String */
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                is.close();

                /* Return the response as string */
                return sb.toString();
            } catch (Exception e) {
                Log.e(TAG, "Error converting result " + e.toString());
            }

            return null;
        }
    }

    /* ===== EVENT OBJECTS ===== */
    /**
     * List of event listeners.
     */
    protected EventListenerList listenerList = new EventListenerList();

    /**
     * Add a new EssemmessListener to the list.
     * 
     * @param listener
     */
    public void addEssemmessEventListener(EssemmessListener listener) {
        listenerList.add(EssemmessListener.class, listener);
    }

    /**
     * Remove the selected EssemmessListener from the list.
     * 
     * @param listener
     */
    public void removeEssemmessEventListener(EssemmessListener listener) {
        listenerList.remove(EssemmessListener.class, listener);
    }

    /**
     * Dispatches a new PUBLISH event, this is dispatched when the HttpWorker
     * has executed a PUBLISH action on the Essemmess server.
     * 
     * @param evt
     */
    private void dispatchEssemmessEvent(EssemmessEvent evt) {
        Object[] listeners = listenerList.getListenerList();
        // Each listener occupies two elements - the first is the listener class
        // and the second is the listener instance
        for (int i = 0; i < listeners.length; i += 2) {
            if (listeners[i] == EssemmessListener.class) {
                /* Fire the correct event type */
                if (evt.getEventType() == EssemmessEvent.LOGIN)
                    ((EssemmessListener) listeners[i + 1]).essemmessLogin((EssemmessLoginEvent) evt);
                else if (evt.getEventType() == EssemmessEvent.READ)
                    ((EssemmessListener) listeners[i + 1]).essemmessRead((EssemmessReadEvent) evt);
                else if (evt.getEventType() == EssemmessEvent.WRITE)
                    ((EssemmessListener) listeners[i + 1]).essemmessWrite((EssemmessWriteEvent) evt);
                else if (evt.getEventType() == EssemmessEvent.REGISTER)
                    ((EssemmessListener) listeners[i + 1]).essemmessRegister((EssemmessRegisterEvent) evt);

            }
        }
    }
}