/** 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(); } } }