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;
}
}