package com.appdynamics.demo.gasp.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import com.appdynamics.demo.gasp.R;
import com.appdynamics.demo.gasp.adapter.GaspDatabase;
import com.appdynamics.demo.gasp.gcm.GCMIntentService;
import com.appdynamics.demo.gasp.gcm.GaspRegistrationClient;
import com.appdynamics.demo.gasp.location.GaspPlaces;
import com.appdynamics.demo.gasp.location.GaspSearch;
import com.appdynamics.demo.gasp.model.Place;
import com.appdynamics.demo.gasp.model.PlaceDetails;
import com.appdynamics.demo.gasp.model.Places;
import com.appdynamics.demo.gasp.model.Query;
import com.appdynamics.demo.gasp.model.Restaurant;
import com.appdynamics.demo.gasp.model.SearchResult;
import com.appdynamics.demo.gasp.service.RestaurantSyncService;
import com.appdynamics.demo.gasp.service.ReviewSyncService;
import com.appdynamics.demo.gasp.service.UserSyncService;
import com.appdynamics.demo.gasp.twitter.TwitterAuthentication;
import com.appdynamics.demo.gasp.utils.LocationServices;
import com.appdynamics.demo.gasp.utils.Network;
import com.appdynamics.demo.gasp.utils.PlayServices;
import com.appdynamics.demo.gasp.utils.Preferences;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import java.util.HashMap;
import com.appdynamics.eumagent.runtime.Instrumentation;
/**
* Copyright (c) 2013 Mark Prichard
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class LocationsActivity extends FragmentActivity {
private static final String TAG = LocationsActivity.class.getName();
// Google Maps and Location
private GoogleMap mMap;
private float mZoom = 16;
private Location mLocation;
// Incremental search results from Google Places API
private SearchResult mSearchResult = new SearchResult();
// Next page token for Google Places API queries
private String mPageToken = "";
// Bundle serialization keys
private static final String PAGE_TOKEN = "PAGE_TOKEN";
private static final String SEARCH_RESULT = "SEARCH_RESULT";
private static final String ZOOM_LEVEL = "ZOOM_LEVEL";
// Gasp proxy objects
private final GaspSearch mGaspSearch = new GaspSearch() {
@Override
public void onSuccess(Places places) {
mSearchResult.add(places);
showLocations(mSearchResult);
checkToken(places);
}
@Override
public void onFailure(String status) {
Log.e(TAG, "Google Places API search failed: status = " + status);
}
};
private final GaspPlaces mGaspPlaces = new GaspPlaces() {
@Override
public void onSuccess(PlaceDetails placeDetails) {
launchPlacesDetailActivity(placeDetails);
}
@Override
public void onFailure(String status) {
Log.e(TAG, "Google Places API search failed: status = " + status);
}
};
private final GaspDatabase mGaspDatabase = new GaspDatabase(this);
// Map GoogleMap Markers to Place Ids
private final HashMap<String, String> mPlacesMap = new HashMap<String, String>();
// Map Place Ids to Reference strings
private final HashMap<String, String> mReferencesMap = new HashMap<String, String>();
// On initial load, we need to wait for Gasp data sync before drawing location markers
private static boolean waitForSync = true;
public static final String SYNC_COMPLETED = "gasp-sync";
// Proxy to handle Gasp GCM registration services
private final GaspRegistrationClient mGaspRegistrationClient = new GaspRegistrationClient();
/**
* Start Gasp data synchronization services
* Handle initial REST sync and GCM updates
*/
private void startDataSyncServices() {
Intent reviewsIntent = new Intent(this, ReviewSyncService.class);
reviewsIntent.putExtra(GCMIntentService.PARAM_IN_MSG, "reviews");
startService(reviewsIntent);
Intent restaurantsIntent = new Intent(this, RestaurantSyncService.class);
restaurantsIntent.putExtra(GCMIntentService.PARAM_IN_MSG, "restaurants");
startService(restaurantsIntent);
Intent usersIntent = new Intent(this, UserSyncService.class);
usersIntent.putExtra(GCMIntentService.PARAM_IN_MSG, "users");
startService(usersIntent);
}
/**
* Button Listener for "More Locations" button
*/
private void addButtonListener() {
Button placesButton = (Button) findViewById(R.id.places_button);
placesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getLocations();
}
});
}
/**
* Click listener for Google Maps markers
*/
private void setMarkerClickListener() {
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
Log.d(TAG, "Place Id: " + mPlacesMap.get(marker.getId()));
Log.d(TAG, "Reference: " + mReferencesMap.get(mPlacesMap.get(marker.getId())));
mGaspPlaces.placeDetails(new Query(mReferencesMap.get(mPlacesMap.get(marker.getId()))));
return false;
}
});
}
/**
* Set Camera for Google Maps API
*/
private void setCamera() {
try {
LatLng myLocation = new LatLng(mLocation.getLatitude(), mLocation.getLongitude());
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(myLocation)
.zoom(mZoom)
.bearing(0)
.tilt(0)
.build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Do Google Places API search (centred on current location, radius from shared preferences)
*/
private void getLocations() {
try {
Preferences preferences = new Preferences(this);
Query query = new Query(mLocation.getLatitude(),
mLocation.getLongitude(),
Preferences.getGaspSearchRadius(),
mPageToken);
mGaspSearch.nearbySearch(query);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Display location via Google Maps API
* @param searchResult Gasp! Locations to display
*/
private void showLocations(SearchResult searchResult) {
Restaurant restaurant;
float markerColour;
try {
for (Place place : searchResult.getPlaces()) {
LatLng pos = new LatLng(place.getGeometry().getLocation().getLat().doubleValue(),
place.getGeometry().getLocation().getLng().doubleValue());
restaurant = mGaspDatabase.getRestaurantByPlacesId(place.getId());
if (restaurant != null)
markerColour = BitmapDescriptorFactory.HUE_GREEN;
else
markerColour = BitmapDescriptorFactory.HUE_RED;
Marker marker =
mMap.addMarker(
new MarkerOptions()
.position(pos)
.title(place.getName())
.icon(BitmapDescriptorFactory.defaultMarker(markerColour)));
Log.d(TAG, place.getName() + " " + pos.toString());
mPlacesMap.put(marker.getId(), place.getId());
mReferencesMap.put(place.getId(), place.getReference());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Check Google Places API search result for page_token
* Indicates more results available: enable "More Locations" button
* See @link{https://developers.google.com/places/documentation/search} for details
* @param places Google Places API return (converted from JSON)
*/
private void checkToken(Places places) {
try {
if (places.getNext_page_token() == null) {
mPageToken = "";
setPlacesButton(false);
} else {
mPageToken = places.getNext_page_token();
Log.d(TAG, "Next page token: " + mPageToken);
setPlacesButton(true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Launch child activity to display details for selected Gasp! location
* @param placeDetails Details for Gasp! location
*/
private void launchPlacesDetailActivity(PlaceDetails placeDetails) {
try {
Intent intent = new Intent();
intent.setClass(LocationsActivity.this, PlacesDetailActivity.class);
intent.putExtra(PlacesDetailActivity.PLACES_DETAIL_SERIALIZED, placeDetails.getResult());
intent.putExtra(PlacesDetailActivity.PLACES_DETAIL_REFERENCE, mReferencesMap.get(placeDetails.getResult().getId()));
startActivityForResult(intent, 0);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Enable/disable "More Locations" button
* @param enableButton enable or disable button
*/
private void setPlacesButton(boolean enableButton) {
Button placesButton = (Button) findViewById(R.id.places_button);
placesButton.setText("More Locations");
if (enableButton) {
placesButton.setEnabled(true);
} else {
placesButton.setEnabled(false);
}
}
/**
* BroadcastReceiver for notification that Gasp! data sync completed
*/
private final BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Restaurant sync completed");
getLocations();
}
};
/**
* Load Google Maps view/fragment, set location and button/click listeners
*/
private void prepareMapView() {
setContentView(R.layout.gasp_locations_layout);
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
mMap.setMyLocationEnabled(true);
setCamera();
addButtonListener();
setMarkerClickListener();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Instrumentation.start("EUM-AAB-AUB",
getApplicationContext(),
"http://ec2-54-214-82-33.us-west-2.compute.amazonaws.com",
true);
mGaspRegistrationClient.registerGCM(this);
TwitterAuthentication.requestTwitterOAuthToken(this);
LocationServices.enableLocationChecking(this);
mLocation = LocationServices.getLocation(this);
// Activity first created
if (savedInstanceState == null) {
// We need Play Services and Network connectivity
if (PlayServices.checkPlayServices(this) && Network.checkNetworking(this)) {
// Register listener for notification that restaurant data has been synced
LocalBroadcastManager.getInstance(this)
.registerReceiver(mMessageReceiver, new IntentFilter(SYNC_COMPLETED));
// Start data sync services and draw map
startDataSyncServices();
prepareMapView();
}
else {
Log.e(TAG, "Cannot launch LocationsActivity");
finish();
}
}
// Subsequent onCreate() events
else {
// Restore incremental search results, page_token and zoom level
mSearchResult = (SearchResult) savedInstanceState.getSerializable(SEARCH_RESULT);
mPageToken = savedInstanceState.getString(PAGE_TOKEN);
mZoom = savedInstanceState.getFloat(ZOOM_LEVEL);
// Display locations and enable/disable "More Locations" button
prepareMapView();
showLocations(mSearchResult);
if (! mPageToken.isEmpty()) {
setPlacesButton(true);
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
/*
// (Re-)register with Gasp GCM Server
case R.id.options_register:
mGaspRegistrationClient.doRegisterGasp(this);
return true;
// Unregister with Gasp GCM Server
case R.id.options_unregister:
mGaspRegistrationClient.doUnregisterGasp(this);
return true;
case R.id.options_exit:
finish();
return true;
*/
case R.id.gasp_settings:
Intent intent = new Intent();
intent.setClass(LocationsActivity.this, SetPreferencesActivity.class);
startActivityForResult(intent, 0);
return true;
case R.id.gasp_menu_twitter:
intent = new Intent();
intent.setClass(LocationsActivity.this, TwitterStreamActivity.class);
startActivityForResult(intent, 0);
return true;
case R.id.gasp_data:
intent = new Intent();
intent.setClass(LocationsActivity.this, GaspDataActivity.class);
startActivityForResult(intent, 0);
return true;
/*
case R.id.gasp_reviews_data:
intent = new Intent();
intent.setClass(LocationsActivity.this, ReviewListActivity.class);
startActivityForResult(intent, 0);
return true;
case R.id.gasp_restaurants_data:
intent = new Intent();
intent.setClass(LocationsActivity.this, RestaurantListActivity.class);
startActivityForResult(intent, 0);
return true;
case R.id.gasp_users_data:
intent = new Intent();
intent.setClass(LocationsActivity.this, UserListActivity.class);
startActivityForResult(intent, 0);
return true;
*/
case R.id.gasp_login_with_amazon:
intent = new Intent();
intent.setClass(LocationsActivity.this, AmazonSignInActivity.class);
startActivityForResult(intent, 0);
return true;
case R.id.gasp_login_with_google:
intent = new Intent();
intent.setClass(LocationsActivity.this, GoogleSignInActivity.class);
startActivityForResult(intent, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onDestroy() {
mGaspRegistrationClient.doUnregisterGasp(this);
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save incremental search results, page_token and zoom level
outState.putSerializable(SEARCH_RESULT, mSearchResult);
outState.putString(PAGE_TOKEN, mPageToken);
outState.putFloat(ZOOM_LEVEL, mMap.getCameraPosition().zoom);
}
}