Subversion Repositories Code-Repo

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

package org.vt.ece4564.latmb;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import org.jboss.netty.channel.Channel;
import org.vt.ece4564.latmb.LATMBProtocol.Message;
import org.vt.ece4564.latmb.LATMBProtocol.Message.Builder;
import org.vt.ece4564.latmb.LATMBProtocol.Position;
import org.vt.ece4564.latmb.LATMBProtocol.TrackingMessage;
import org.vt.ece4564.latmb.LATMBProtocol.DateTime;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MessageBoardActivity extends Activity implements OnClickListener, 
                LocationListener, NetworkMessageHandler<TrackingMessage> {
        
        private static final String TAG = MessageBoardActivity.class.getName();
        
        private EditText newEntry_;
        private Button submit_;
        private TextView status_;
        private ViewGroup messageContainer_;
        
        private String server_;
        private int port_;
        private String username_;
        private String chatroom_;
        private boolean useGPS_;
        private boolean gpsAcquired_ = false;
        private boolean gpsChanged_ = false;
        
        private Handler handler_ = new Handler();
        
        private Boolean connected_ = false;
        private long reconnectInterval_ = 5000;
        private boolean autoReconnect_ = false;
        
        private double latitude_ = 0;
        private double longitude_ = 0;
        private double radius_ = 0;
        
        private LocationManager locationManager_;
        
        private ClientHandler<LATMBProtocol.TrackingMessage> msgHandler_;
        
        // List of messages stored locally
        private static List<LATMBMessage> storedMessages_ = new ArrayList<LATMBMessage>();
        
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                // Create the menu
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.messagemenu, menu);
            return true;
        }
        
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle item selection
            switch (item.getItemId()) {
            case R.id.menuPreferences:
                startActivity(new Intent(this, PreferenceActivity.class));
                return true;
            case R.id.menuDisconnect:
                disconnectFromServer();
                return true;
            case R.id.menuChangeChatroom:
                finish();
                return true;
            case R.id.menuRefresh:
                storedMessages_.clear();
                getInitialMessages();
                return true;
            default:
                return super.onOptionsItemSelected(item);
            }
        }
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                setContentView(R.layout.messageboard);

                newEntry_ = (EditText) findViewById(R.id.editMessage);
                submit_ = (Button) findViewById(R.id.buttonSubmit);
                status_ = (TextView) findViewById(R.id.textStatus);
                messageContainer_ = (ViewGroup) findViewById(R.id.messageList);
                
                Intent i = getIntent();
                server_ = i.getStringExtra("server");
                port_ = Integer.parseInt(i.getStringExtra("port"));
                username_ = i.getStringExtra("username");
                chatroom_ = i.getStringExtra("chatroom");
                useGPS_ = i.getBooleanExtra("gps", false);
                radius_ = i.getDoubleExtra("radius", 1);
                
                submit_.setOnClickListener(this);
                
                locationManager_ = (LocationManager) getSystemService(LOCATION_SERVICE);
        }
        
        @Override
        protected void onPause() {
                super.onPause();
                
                // Stop the GPS updater if location is used
                if (useGPS_) {
                        locationManager_.removeUpdates(this);
                }
                stopAutoReconnect();
                disconnectFromServer();
        }

        @Override
        protected void onResume() {
                super.onResume();
                
                // Start the GPS updater if location is used
                if (useGPS_) {
                        locationManager_.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
                }
                startAutoReconnect();
        }
        
        @Override
        public void onClick(View arg0) {
                // Send message if client is connected to server and location is acquired (only if gps is used)
                if ((connected_ && !useGPS_) || (connected_ && gpsAcquired_)) {
                        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
                        
                        String text = newEntry_.getText().toString();
                        
                        Calendar c = Calendar.getInstance();
                        DateTime timestamp = DateTime.newBuilder()
                                        .setYear(c.get(Calendar.YEAR))
                                        .setMonth(c.get(Calendar.MONTH))
                                        .setDay(c.get(Calendar.DAY_OF_MONTH))
                                        .setHour(c.get(Calendar.HOUR_OF_DAY))
                                        .setMinute(c.get(Calendar.MINUTE))
                                        .setSecond(c.get(Calendar.SECOND))
                                        .build();
                        
                        // Get the expiration time from saved preferences
                        int exp_days = Integer.parseInt(sharedPrefs.getString("pref_MessageExpiration_Days", "1"));
                        int exp_months = Integer.parseInt(sharedPrefs.getString("pref_MessageExpiration_Months", "0"));
                        int exp_hours = Integer.parseInt(sharedPrefs.getString("pref_MessageExpiration_Hours", "0"));
                        int exp_minutes = Integer.parseInt(sharedPrefs.getString("pref_MessageExpiration_Minutes", "0"));

                        c.add(Calendar.DAY_OF_MONTH, exp_days);
                        c.add(Calendar.MONTH, exp_months);
                        c.add(Calendar.HOUR_OF_DAY, exp_hours);
                        c.add(Calendar.MINUTE, exp_minutes);
                        
                        DateTime expiration = DateTime.newBuilder()
                                        .setYear(c.get(Calendar.YEAR))
                                        .setMonth(c.get(Calendar.MONTH))
                                        .setDay(c.get(Calendar.DAY_OF_MONTH))
                                        .setHour(c.get(Calendar.HOUR_OF_DAY))
                                        .setMinute(c.get(Calendar.MINUTE))
                                        .setSecond(c.get(Calendar.SECOND))
                                        .build();
                        
                        Builder message = Message.newBuilder()
                                        .setMessage(text)
                                        .setTimestamp(timestamp)
                                        .setExpiration(expiration);
                        
                        if (!username_.isEmpty()) {
                                message.setUsername(username_);
                        }
                        if (!useGPS_) {
                                message.setChatroom(chatroom_);
                        } else {
                                Position pos = Position.newBuilder()
                                                .setLatitude(latitude_)
                                                .setLongitude(longitude_)
                                                .setAccuracy(0)
                                                .build();
                                message.setRadius(radius_);
                                message.setCoordinates(pos);
                        }
                        
                        TrackingMessage msg = TrackingMessage.newBuilder()
                                        // Type 1 == New Message
                                        .setId(0).setType(1)
                                        .addMessage(message)
                                        .build();
                        
                        // Send the message to the server
                        msgHandler_.send(msg);
                        
                        newEntry_.setText("");
                }
        }

        private boolean connectToServer(String server, int port) {
                try {
                        synchronized (connected_) {
                                if (connected_)
                                        return true;

                                updateStatus("Connecting to server...");

                                msgHandler_ = LATMBClient.connect(server, port);
                                msgHandler_.setListener(this);
                                connected_ = true;
                                
                                // Remove all currently saved messages
                                storedMessages_.clear();
                                
                                if (!useGPS_) {
                                        getInitialMessages();
                                }
                                // Start the thread to check for expired messages
                                startUpdaterThread();
                                
                                updateStatus("Connected to server [" + server + ":" + port + "]");
                        }
                        return true;
                } catch (Exception e) {
                        Log.e(TAG, "Unable to connect to server", e);
                        return false;
                }

        }
        
        private class ConnectWorker implements Runnable {

                public void run() {
                        doConnect();
                }

                public void doConnect() {
                        try {
                                while (autoReconnect_ && !connectToServer(server_, port_)) {
                                        updateStatus("Attempting to reconnect to server...");
                                        Thread.currentThread().sleep(reconnectInterval_);
                                }
                        } catch (Exception e) {
                                doConnect();
                        }
                }
        }
        
        private void startAutoReconnect() {
                autoReconnect_ = true;
                ConnectWorker w = new ConnectWorker();
                Thread t = new Thread(w);
                t.start();

        }

        private void stopAutoReconnect() {
                autoReconnect_ = false;
        }
        
        private void disconnectFromServer() {
                synchronized (connected_) {
                        connected_ = false;
                        msgHandler_.disconnect();
                }
        }
        
        private void updateStatus(final String status) {
                handler_.post(new Runnable() {
                        
                        @Override
                        public void run() {
                                status_.setText(status);
                        }
                });
        }
        
        private void startUpdaterThread() {
                Thread t = new Thread(new Runnable() {

                        @Override
                        public void run() {
                                while (true) {
                                        try {
                                                // If a new GPS coordinate is set, pull new list of messages
                                                if (gpsChanged_ && gpsAcquired_) {
                                                        storedMessages_.clear();
                                                        getInitialMessages();
                                                        gpsChanged_ = false;
                                                }
                                                // Refresh the display
                                                updateMessageUI();
                                                Thread.currentThread().sleep(5000);
                                        } catch (Exception e) {
                                                e.printStackTrace();
                                        }
                                }
                        }
                });
                t.start();
        }
        
        private void getInitialMessages() {
                Runnable r = new Runnable() {

                        @Override
                        public void run() {
                                if (connected_) {
                                        Calendar c = Calendar.getInstance();
                                        DateTime timestamp = DateTime.newBuilder()
                                                        .setYear(c.get(Calendar.YEAR))
                                                        .setMonth(c.get(Calendar.MONTH))
                                                        .setDay(c.get(Calendar.DAY_OF_MONTH))
                                                        .setHour(c.get(Calendar.HOUR_OF_DAY))
                                                        .setMinute(c.get(Calendar.MINUTE))
                                                        .setSecond(c.get(Calendar.SECOND))
                                                        .build();
                                        
                                        Builder message = Message.newBuilder()
                                                        .setMessage("")
                                                        .setTimestamp(timestamp)
                                                        .setExpiration(timestamp);
                                        
                                        if (!username_.isEmpty()) {
                                                message.setUsername(username_);
                                        }
                                        if (!useGPS_) {
                                                message.setChatroom(chatroom_);
                                        } else {
                                                Position pos = Position.newBuilder()
                                                                .setLatitude(latitude_)
                                                                .setLongitude(longitude_)
                                                                .setAccuracy(0)
                                                                .build();
                                                message.setRadius(radius_);
                                                message.setCoordinates(pos);
                                        }
                                        
                                        TrackingMessage msg = TrackingMessage.newBuilder()
                                                        // Type 0 == Initial Message
                                                        .setId(0).setType(0)
                                                        .addMessage(message)
                                                        .build();
                                        
                                        msgHandler_.send(msg);
                                }
                        }
                };
                handler_.post(r);
        }
        
        @Override
        public void onLocationChanged(Location location) {
                latitude_ = location.getLatitude();
                longitude_ = location.getLongitude();
                if (latitude_ != 0 && longitude_ != 0) {
                        gpsChanged_ = true;
                        gpsAcquired_ = true;
                }
        }

        @Override
        public void onProviderDisabled(String arg0) {
                updateStatus("GPS is disabled");
                Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(intent);
        }

        @Override
        public void onProviderEnabled(String arg0) {
                updateStatus("GPS is enabled");
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle bundle) {
                switch (status) {
                case LocationProvider.OUT_OF_SERVICE:
                        Toast.makeText(this, "GPS Status Changed: Out of Service", Toast.LENGTH_SHORT).show();
                        break;
                case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        Toast.makeText(this, "GPS Status Changed: Temporarily Unavailable", Toast.LENGTH_SHORT).show();
                        break;
                case LocationProvider.AVAILABLE:
                        Toast.makeText(this, "GPS Status Changed: Available", Toast.LENGTH_SHORT).show();
                        break;
                }
                
        }

        
        @Override
        public void received(final TrackingMessage msg) {
                Runnable r = new Runnable() {
                        
                        @Override
                        public void run() {
                                
                                // Create a LATMBMessage from the TrackingMessage and store it
                                List<Message> messages = msg.getMessageList();

                                for (int i = 0; i < messages.size(); i++) {
                                        Message message = messages.get(i);
                                        
                                        DateTime timestamp = message.getTimestamp();
                                        DateTime expiration = message.getExpiration();
                                        
                                        LATMBMessage newEntry = new LATMBMessage();
                                        
                                        newEntry.setMessage(message.getMessage());
                                        
                                        Calendar time = new GregorianCalendar();
                                        time.set(timestamp.getYear(), timestamp.getMonth(), timestamp.getDay(), 
                                                        timestamp.getHour(), timestamp.getMinute(), timestamp.getSecond());
                                        newEntry.setTimestamp(time);
                                        
                                        Calendar exp = new GregorianCalendar();
                                        exp.set(expiration.getYear(), expiration.getMonth(), expiration.getDay(), 
                                                        expiration.getHour(), expiration.getMinute(), expiration.getSecond());
                                        newEntry.setExpiration(exp);
                                        
                                        if (message.hasUsername()) {
                                                newEntry.setUsername(message.getUsername());
                                        } else {
                                                newEntry.setUsername("Anonymous");
                                        }
                                        
                                        if (message.hasChatroom()) {
                                                newEntry.setChatroom(message.getChatroom());
                                        }
                                        
                                        if (message.hasCoordinates()) {
                                                Position coord = message.getCoordinates();
                                                newEntry.setLatitude(coord.getLatitude());
                                                newEntry.setLongitude(coord.getLongitude());
                                        }
                                        
                                        if (message.hasRadius()) {
                                                newEntry.setRadius(message.getRadius());
                                        }
                                        
                                        storedMessages_.add(newEntry);
                                }
                        }
                };
                handler_.post(r);
                updateMessageUI();
        }

        // Updates the GUI to show stored entries
        public void updateMessageUI() {
                Runnable r = new Runnable() {

                        @Override
                        public void run() {
                                if (connected_) {
                                        // Show the current chatroom or the current GPS coordinates
                                        if (!useGPS_) {
                                                updateStatus("Current chatroom: " + chatroom_);
                                        } else {
                                                if (!gpsAcquired_) {
                                                        updateStatus("Waiting for location...");
                                                } else {
                                                        updateStatus("Using location (" + latitude_ + "," + longitude_ + ")");
                                                }
                                        }
                                }
                                
                                removeExpiredMessages();
                                
                                messageContainer_.removeAllViews();
                                
                                // Print each message
                                for (LATMBMessage message : storedMessages_) {
                                        Calendar time = message.getTimestamp();
                                        String msg = String.format("%d/%d/%d @ %d:%d:%d ~ %s\n>> %s",
                                                        time.get(Calendar.DAY_OF_MONTH), time.get(Calendar.MONTH),
                                                        time.get(Calendar.YEAR), time.get(Calendar.HOUR_OF_DAY),
                                                        time.get(Calendar.MINUTE), time.get(Calendar.SECOND),
                                                        message.getUsername(), message.getMessage());
                                        TextView v = new TextView(MessageBoardActivity.this);
                                        v.setText(msg);
                                        messageContainer_.addView(v);
                                }
                        }       
                };
                handler_.post(r);
        }
        
        // Removes all stored expired messages
        public void removeExpiredMessages() {
                Runnable r = new Runnable() {

                        @Override
                        public void run() {
                                List<LATMBMessage> toRemove = new ArrayList<LATMBMessage>();
                                for (LATMBMessage message : storedMessages_) {
                                        Calendar c = Calendar.getInstance();
                                        if (c.after(message.getExpiration())) {
                                                toRemove.add(message);
                                        }
                                }
                                for (LATMBMessage message : toRemove) {
                                        storedMessages_.remove(message);
                                }
                        }
                };
                handler_.post(r);
        }
        
        @Override
        public void channelException(Throwable e) {
                updateStatus("Exception occured connecting to server");
                connected_ = false;
        }

        @Override
        public void channelClosed(Channel c) {
                updateStatus("Connection to server closed");
                connected_ = false;
        }

}