/** MapActivity
* The primary activity for the mapping functionality of PurdueApp.
*/
package edu.purdue.app.map;
import java.util.ArrayList;
import java.util.List;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.model.*;
import com.google.android.gms.maps.model.LatLngBounds.Builder;
import edu.purdue.app.R;
import edu.purdue.app.map.BuildingListDialog.OnBuildingSelectedListener;
import edu.purdue.app.map.GoogleMapFragment.GMapFragmentLoadedListener;
import edu.purdue.app.map.MapData.Building;
import edu.purdue.app.map.LayerListDialog.MapLayersUpdateListener;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SearchView;
import android.widget.Toast;
public class MapActivity extends Activity implements MapLayersUpdateListener {
/** Logging tag for all Log.d output generated by the mapping segment of the program */
public static String LOG_MAP_TAG = "PurdueApp-Map";
/** Fragments for the UI */
BuildingListDialog buildingFragment;
GoogleMapFragment gmapFragment;
/** Various class variables */
GoogleMap gmap;
/** This is defined statically so some other parts of the app don't have to instantiate their
* own MapData object, which can take quite a bit of time considering it re-parses the JSON.
* However, be careful about accessing this, because it is instantiated in onCreate(). I can't define
* its instantiation statically because it requires access to Context. */
public static MapData mpd;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Log event
Log.d(LOG_MAP_TAG, "MapActivity : onCreate() called.");
// Set the content view with a google map fragment
setContentView(R.layout.map_activity_main);
// Create the fragments for the UI
MapActivityEventListener eventListener = new MapActivityEventListener(this);
gmapFragment = ((GoogleMapFragment) getFragmentManager().findFragmentById(R.id.map_fragment_googlemapfragment));
gmapFragment.setGMapFragmentLoadedListener(eventListener);
buildingFragment = new BuildingListDialog();
buildingFragment.setOnBuildingSelectedListener(eventListener);
// Prepare MapData
mpd = new MapData(this);
// Initialize the gms maps services
try {
MapsInitializer.initialize(this);
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
/** Called when the user initializes a search */
protected void onNewIntent(Intent i) {
// Log event
Log.d(MapActivity.LOG_MAP_TAG, "MapActivity : Intent intercepted : " + i.getAction());
// Executed when the user manually enters a search term and hits enter
if (Intent.ACTION_SEARCH.equals(i.getAction())) {
String searchTerm = i.getStringExtra(SearchManager.QUERY);
Log.d(MapActivity.LOG_MAP_TAG, "MapActivity : Manual search for item : " + searchTerm);
search(searchTerm);
}
// Executed when the user selects a search result from the suggestions
else if (Intent.ACTION_VIEW.equals(i.getAction())) {
Building l = mpd.searchBuilding(i.getData().toString());
Log.d(MapActivity.LOG_MAP_TAG, "MapActivity : Suggestion selected for item : " + l.full_name);
gmapFragment.addPinToMap(new LatLng(l.lat, l.lng), l.full_name, true);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = this.getMenuInflater();
inflater.inflate(R.menu.map_actionbarmenu, menu);
// Makes the search button the action bar turn into a search box on click.
SearchManager searchman = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView sv = (SearchView) menu.findItem(R.id.map_actionbar_searchbuildings).getActionView();
sv.setSearchableInfo(searchman.getSearchableInfo(getComponentName()));
sv.setIconifiedByDefault(false);
return true;
}
/** Called when the user selects a button on the action bar or drop-donw settings menu */
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.map_actionbar_listbuildings:
buildingFragment.show(getFragmentManager(), "buildings");
break;
case R.id.map_actionbar_layers:
LayerListDialog dialog = new LayerListDialog();
dialog.setOnUpdateListener(this, this);
dialog.show(getFragmentManager(), "layers");
break;
case R.id.map_actionbar_searchbuildings:
break;
}
return super.onOptionsItemSelected(item);
}
/** Called when the user confirms layer selection in LayersDialog */
public void onLayersUpdate(List<String> enabledLayers) {
// Clear the map
gmap.clear();
// If no layers at all were selected, then reset the camera and return
if (enabledLayers.size() == 0) {
gmap.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(mpd.PURDUE_CENTER_LAT, mpd.PURDUE_CENTER_LNG),
mpd.PURDUE_CAMPUS_ZOOM));
return;
}
// Create a camera update bounds which will be updated as we add pins
LatLngBounds.Builder latlngbuilder = LatLngBounds.builder();
// The list of layers contains each layer the user has selected.
// If the user selects multiple layers then they should be displayed simultaneously
for (String i : enabledLayers) {
for (LatLng loc : mpd.getLayerPoints(i)) {
// Calculate the distance between the user's location and the pin (in meters)
int dBetween = 0;
if (gmap.getMyLocation() != null) {
double dBetweenD = MapData.distanceBetween(gmap.getMyLocation().getLatitude(),
gmap.getMyLocation().getLongitude(), loc.latitude, loc.longitude) * 1000;
// Cast it as an int to chop of the decimal as we really don't care about anything less than 1 meter
dBetween = (int) dBetweenD;
}
// Create a new marker at that position with the title set as the distance
gmap.addMarker(new MarkerOptions()
.position(loc)
.title("" + dBetween + " m"));
latlngbuilder.include(loc);
}
}
// Animate the camera so it includes all the new pins
gmap.animateCamera(CameraUpdateFactory.newLatLngBounds(latlngbuilder.build(), 300));
}
/** Does a search on a given string and adds a pin to the map if it is found.
* Does nothing if the search returned nothing. */
private void search(String s) {
// Do the search, which is in MapData
Building result = mpd.searchBuilding(s);
// The result is null if there are no results, so do nothing.
if (result != null) {
// Add a pin to the map and toast the full name of the building
gmapFragment.addPinToMap(new LatLng(result.lat, result.lng), result.full_name, true);
Toast.makeText(this, result.full_name, Toast.LENGTH_SHORT).show();
}
}
}