package com.magnet.wru;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.magnet.mmx.client.api.MMX;
import com.magnet.mmx.client.api.MMXMessage;
import com.magnet.mmx.client.api.MMXUser;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String TAG = MapActivity.class.getSimpleName();
private WRU mWru = null;
private GoogleMap mMap = null;
private TextView mTextTop = null;
private SupportMapFragment mMapFragment = null;
private MessageListFragment mMessageListFragment = null;
private ImageButton mToggleMessageList = null;
private DateFormat mFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
private MyMessageStore.OnChangeListener mMessageListListener = new MyMessageStore.OnChangeListener() {
public void onChange() {
if (!mMessageListOpen) {
runOnUiThread(new Runnable() {
public void run() {
mToggleMessageList.setBackgroundColor(getResources().getColor(android.R.color.holo_green_light));
}
});
}
}
};
private WRU.OnLocationReceivedListener mListener = new WRU.OnLocationReceivedListener() {
public void onLocationReceived(MMXUser user, WRU.LocationTime locationTime) {
updateLocationMarkers(locationTime);
}
};
private MMX.EventListener mEventListener = new MMX.EventListener() {
@Override
public boolean onMessageReceived(MMXMessage mmxMessage) {
return false;
}
public boolean onLoginRequired(MMX.LoginReason reason) {
updateLoginState();
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
mWru = WRU.getInstance(this);
mWru.registerOnLocationReceivedListener(mListener);
mTextTop = (TextView) findViewById(R.id.text_top);
mTextTop.setText("group key: " + mWru.getJoinedTopicKey() + ", passphrase: " + mWru.getJoinedTopicPassphrase());
mToggleMessageList = (ImageButton) findViewById(R.id.toggle_message_list);
//setup map
mMapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mMapFragment.getMapAsync(this);
mMessageListFragment = (MessageListFragment) getSupportFragmentManager()
.findFragmentById(R.id.fragment_message_list);
MyMessageStore.registerListener(mMessageListListener);
MMX.registerListener(mEventListener);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
updateLoginState();
}
}, 3000);
}
protected void onResume() {
updateLocationMarkers(null);
MyMessageStore.sSuppressNotification = true;
super.onResume();
}
protected void onPause() {
MyMessageStore.sSuppressNotification = false;
super.onPause();
}
protected void onDestroy() {
mWru.unregisterOnLocationReceivedListener(mListener);
MyMessageStore.unregisterListener(mMessageListListener);
MMX.unregisterListener(mEventListener);
super.onDestroy();
}
@Override
public void onMapReady(GoogleMap map) {
mMap = map;
mMap.setMyLocationEnabled(true);
mMap.setTrafficEnabled(true);
AsyncTask.execute(new Runnable() {
public void run() {
GoogleApiClient googleApiClient = mWru.waitForGoogleApi();
Log.d(TAG, "onMapReady(): requesting last location");
Location result = LocationServices.FusedLocationApi
.getLastLocation(googleApiClient);
if (result != null) {
final LatLng myloc = new LatLng(result.getLatitude(),
result.getLongitude());
runOnUiThread(new Runnable() {
public void run() {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(myloc, 16));
}
});
}
}
});
updateLocationMarkers(null);
}
private HashMap<String, Marker> mMarkerMap = new HashMap<>();
private HashMap<String, Circle> mCircleMap = new HashMap<>();
private void updateLocationMarkers(final WRU.LocationTime locationTime) {
if (locationTime == null) {
for (WRU.LocationTime entry : mWru.getLocationTimes().values()) {
updateMarker(entry);
}
} else {
updateMarker(locationTime);
}
}
private void updateMarker(final WRU.LocationTime locationTime) {
runOnUiThread(new Runnable() {
public void run() {
if (mMap == null) {
Log.w(TAG, "updateMarker(): map is not ready yet, ignoring");
return;
}
if (!locationTime.username.equalsIgnoreCase(mWru.getUsername())) {
Marker marker = mMarkerMap.get(locationTime.username);
Circle circle = mCircleMap.get(locationTime.username);
LatLng loc = new LatLng(locationTime.location.getLat(), locationTime.location.getLng());
StringBuilder snippet = new StringBuilder()
.append("+/-").append(locationTime.location.getAccuracy()).append("m, fix: ")
.append(mFormatter.format(new Date(locationTime.locationTimestamp)))
.append(", rcv: ")
.append(mFormatter.format(new Date(locationTime.timestamp)));
if (marker == null) {
String label = locationTime.username;
marker = mMap.addMarker(new MarkerOptions().position(loc).title(label).snippet(snippet.toString()));
mMarkerMap.put(locationTime.username, marker);
//draw the circle
mCircleMap.put(locationTime.username, mMap.addCircle(
new CircleOptions()
.center(marker.getPosition())
.radius(locationTime.location.getAccuracy())
.strokeColor(0xffff0000)
.strokeWidth(1.0f)
.fillColor(0x44ff0000)));
} else {
marker.setSnippet(snippet.toString());
marker.setPosition(loc);
if (marker.isInfoWindowShown()) {
//refresh the marker info window
marker.hideInfoWindow();
marker.showInfoWindow();
}
circle.setCenter(marker.getPosition());
circle.setRadius(locationTime.location.getAccuracy());
}
marker.setAlpha(getTimeBasedAlpha(locationTime.locationTimestamp));
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_map, menu);
MenuItem item = menu.findItem(R.id.action_set_enabled);
EventLog eventLog = EventLog.getInstance(this);
if (eventLog.isEnabled()) {
item.setTitle(R.string.action_disable);
} else {
item.setTitle(R.string.action_enable);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.action_settings)
.setMessage("YOU ARE: " + mWru.getUsername() + "\nGROUP KEY: " + mWru.getJoinedTopicKey() +
"\nPASSPHRASE: " + mWru.getJoinedTopicPassphrase())
.show();
return true;
}
if (id == R.id.action_request_updates) {
mWru.requestLocationUpdates();
return true;
}
if (id == R.id.action_leave) {
mWru.leaveTopic();
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
this.finish();
return true;
}
if (id == R.id.action_find) {
final String[] users = new String[mMarkerMap.size()];
mMarkerMap.keySet().toArray(users);
ArrayList<String> tmpList = new ArrayList<>();
Collections.addAll(tmpList, users);
Collections.sort(tmpList, new SortIgnoreCase());
tmpList.toArray(users);
final AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.action_find)
.setItems(users, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String user = users[which];
Marker marker = mMarkerMap.get(user);
marker.showInfoWindow();
LatLngBounds.Builder builder = new LatLngBounds.Builder()
.include(marker.getPosition());
Location myLoc = mMap.getMyLocation();
if (myLoc != null) {
builder.include(new LatLng(mMap.getMyLocation().getLatitude(),
mMap.getMyLocation().getLongitude()));
}
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 40));
dialog.dismiss();
}
})
.show();
}
if (id == R.id.action_clear_log) {
EventLog.getInstance(this).clear();
}
if (id == R.id.action_view_log) {
List<EventLog.Event> events = EventLog.getInstance(this).listEvents(null, 50);
final String[] eventStrs = new String[events.size()];
for (int i=0; i<events.size(); i++) {
EventLog.Event event = events.get(i);
eventStrs[i] = mFormatter.format(event.timestamp) + " " + event.type + ": " + event.text;
}
final AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.action_view_log)
.setItems(eventStrs, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
AlertDialog messageDialog = new AlertDialog.Builder(MapActivity.this)
.setMessage(eventStrs[which])
.show();
}
})
.show();
}
if (id == R.id.action_set_enabled) {
EventLog eventLog = EventLog.getInstance(this);
eventLog.setEnabled(!eventLog.isEnabled());
item.setTitle(eventLog.isEnabled() ? R.string.action_disable : R.string.action_enable);
Toast.makeText(this, "Event log is " + (eventLog.isEnabled() ? "enabled" : "disabled"), Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}
private static final float MARKER_MIN_ALPHA = 0.2f;
private static final float MILLIS_IN_HOUR = 60 * 60 * 1000f;
private float getTimeBasedAlpha(long locationTime) {
// we will use a 1 hr window for opacity meaning at 1hr age,
// the marker should be transparent (or at least min alpha)
long age = System.currentTimeMillis() - locationTime;
float calculatedFloat = (MILLIS_IN_HOUR - age) / MILLIS_IN_HOUR;
Log.d(TAG, "getTimeBasedAlpha(): calculated float = " + String.valueOf(calculatedFloat));
return calculatedFloat < MARKER_MIN_ALPHA ? MARKER_MIN_ALPHA : calculatedFloat;
}
public class SortIgnoreCase implements Comparator<Object> {
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
return s1.toLowerCase().compareTo(s2.toLowerCase());
}
}
public void doFragmentClick(View view) {
mMessageListFragment.doFragmentClick(view);
}
private boolean mMessageListOpen = false;
public synchronized void toggleMessageList(View view) {
float newWeight;
if (mMessageListOpen) {
//hide soft keyboard
InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
newWeight = 0;
} else {
mToggleMessageList.setBackgroundColor(getResources().getColor(android.R.color.darker_gray));
newWeight = 9;
}
mMessageListFragment.getView()
.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, newWeight));
mMessageListOpen = !mMessageListOpen;
}
private void updateLoginState() {
runOnUiThread(new Runnable() {
public void run() {
if (MMX.getCurrentUser() != null) {
//logged in
mToggleMessageList.setBackgroundColor(getResources().getColor(android.R.color.holo_green_light));
} else {
//not logged in
mToggleMessageList.setBackgroundColor(getResources().getColor(android.R.color.holo_red_dark));
}
}
});
}
}