From f0136fb2d39ca1090cf5c46cbe49bd3ef54e969c Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sat, 10 Jun 2017 01:42:49 +0300 Subject: [PATCH] Added map, JSON requests and clusters --- app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 2 +- .../fishrungames/yelpmapapp/DataProvider.kt | 50 +++++++ .../yelpmapapp/HandleResponseAsyncTask.kt | 52 +++++++ .../yelpmapapp/MapMarkerClusterItem.kt | 21 +++ .../yelpmapapp/MapMarkerRecord.kt | 14 ++ .../fishrungames/yelpmapapp/MapsActivity.kt | 59 ++++---- .../yelpmapapp/YelpInfoWindowProvider.kt | 32 ++++ .../yelpmapapp/YelpMapActivity.kt | 141 ++++++++++++++++++ app/src/main/res/layout/activity_maps.xml | 2 +- .../main/res/layout/yelp_info_contents.xml | 6 + app/src/main/res/values/strings.xml | 2 +- 12 files changed, 347 insertions(+), 36 deletions(-) create mode 100755 app/src/main/java/fishrungames/yelpmapapp/DataProvider.kt create mode 100755 app/src/main/java/fishrungames/yelpmapapp/HandleResponseAsyncTask.kt create mode 100755 app/src/main/java/fishrungames/yelpmapapp/MapMarkerClusterItem.kt create mode 100755 app/src/main/java/fishrungames/yelpmapapp/MapMarkerRecord.kt create mode 100755 app/src/main/java/fishrungames/yelpmapapp/YelpInfoWindowProvider.kt create mode 100755 app/src/main/java/fishrungames/yelpmapapp/YelpMapActivity.kt create mode 100755 app/src/main/res/layout/yelp_info_contents.xml diff --git a/app/build.gradle b/app/build.gradle index f5a93df..8701f14 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,4 +31,6 @@ dependencies { testImplementation 'junit:junit:4.12' implementation 'com.google.android.gms:play-services-maps:10.2.1' implementation 'com.google.android.gms:play-services-location:10.2.1' + compile 'com.google.maps.android:android-maps-utils:0.4+' + compile 'com.koushikdutta.ion:ion:2.+' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e232557..3e3cd5c 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,7 +29,7 @@ android:value="@string/google_maps_key" /> diff --git a/app/src/main/java/fishrungames/yelpmapapp/DataProvider.kt b/app/src/main/java/fishrungames/yelpmapapp/DataProvider.kt new file mode 100755 index 0000000..2237a6c --- /dev/null +++ b/app/src/main/java/fishrungames/yelpmapapp/DataProvider.kt @@ -0,0 +1,50 @@ +package fishrungames.yelpmapapp + +import android.content.Context +import com.google.gson.JsonArray +import com.koushikdutta.ion.Ion +import java.io.BufferedInputStream +import java.net.HttpURLConnection +import java.net.URL +import java.security.AccessController.getContext +import com.google.gson.JsonObject +import com.koushikdutta.async.future.FutureCallback +import android.os.AsyncTask +import org.json.JSONObject + + +/** + * Created by mephi on 09.06.2017. + */ + +class DataProvider(val context: Context, val onUpdateMapMarkers : ((Map) -> Unit)) { + + val yelpApiKey = "TFhv6H25FV25ETpIC64TmN1sZ98yLIK3-4IZ7-CFSaRIyO6Xo97n1uI5207vo3JA-gLgu1f_7dw4LLWrpAcVAELSVFwHxYDL2FEfwaheJ9WvjbgEbjd3ADWAkt46WXYx" + + fun requestData(lat : Double, lon : Double, radius : Int) + { + + Ion.with(context) + .load("https://api.yelp.com/v3/businesses/search?latitude=${lat}&longitude=${lon}&radius=${radius}") + .addHeader("Authorization", "Bearer " + yelpApiKey) + .asJsonObject() + .setCallback { e, result -> + + if (e != null) + { + return@setCallback + } + + if (result == null) + { + return@setCallback + } + + HandleResponseAsyncTask(onUpdateMapMarkers).execute(result) + }; + + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/fishrungames/yelpmapapp/HandleResponseAsyncTask.kt b/app/src/main/java/fishrungames/yelpmapapp/HandleResponseAsyncTask.kt new file mode 100755 index 0000000..e69e0f3 --- /dev/null +++ b/app/src/main/java/fishrungames/yelpmapapp/HandleResponseAsyncTask.kt @@ -0,0 +1,52 @@ +package fishrungames.yelpmapapp + +import android.os.AsyncTask +import com.google.gson.JsonObject + + +/** + * Created by mephi on 10.06.2017. + */ + + +class HandleResponseAsyncTask(val onUpdateMapMarkers : ((Map) -> Unit)) : AsyncTask>() +{ + + override fun doInBackground(vararg response : JsonObject): Map { + + val newMapMarkers = mutableMapOf() + + try { + + for (businessElement in response[0].getAsJsonArray("businesses")) { + val businessJson = businessElement.asJsonObject + + val id = businessJson.get("id").asString + val name = businessJson.get("name").asString + val image_url = businessJson.get("image_url").asString + val latitude = businessJson.get("coordinates").asJsonObject.get("latitude").asDouble + val longitude = businessJson.get("coordinates").asJsonObject.get("longitude").asDouble + + var mapMarker = MapMarkerRecord(id, name, image_url, latitude, longitude) + + newMapMarkers[name] = mapMarker + + } + + } + catch (e : Exception) + { + e.printStackTrace() + + } + + return newMapMarkers + } + + override fun onPostExecute(result: Map) { + super.onPostExecute(result) + + onUpdateMapMarkers(result) + + } +} \ No newline at end of file diff --git a/app/src/main/java/fishrungames/yelpmapapp/MapMarkerClusterItem.kt b/app/src/main/java/fishrungames/yelpmapapp/MapMarkerClusterItem.kt new file mode 100755 index 0000000..79c59ca --- /dev/null +++ b/app/src/main/java/fishrungames/yelpmapapp/MapMarkerClusterItem.kt @@ -0,0 +1,21 @@ +package fishrungames.yelpmapapp + +import com.google.maps.android.clustering.ClusterItem +import com.google.android.gms.maps.model.LatLng + + + +/** + * Created by mephi on 10.06.2017. + */ + +class MapMarkerClusterItem(inMapMarkerRecord : MapMarkerRecord) : ClusterItem +{ + private val mPosition = LatLng(inMapMarkerRecord.lat, inMapMarkerRecord.lon) + + val mapMarkerRecord = inMapMarkerRecord + + override fun getPosition(): LatLng { + return mPosition + } +} \ No newline at end of file diff --git a/app/src/main/java/fishrungames/yelpmapapp/MapMarkerRecord.kt b/app/src/main/java/fishrungames/yelpmapapp/MapMarkerRecord.kt new file mode 100755 index 0000000..8dd1599 --- /dev/null +++ b/app/src/main/java/fishrungames/yelpmapapp/MapMarkerRecord.kt @@ -0,0 +1,14 @@ +package fishrungames.yelpmapapp + +/** + * Created by mephi on 09.06.2017. + */ + + +data class MapMarkerRecord ( + val id: String, + val name: String, + val imageUrl: String, + val lat: Double, + val lon: Double +) diff --git a/app/src/main/java/fishrungames/yelpmapapp/MapsActivity.kt b/app/src/main/java/fishrungames/yelpmapapp/MapsActivity.kt index 31d38f3..ac13933 100755 --- a/app/src/main/java/fishrungames/yelpmapapp/MapsActivity.kt +++ b/app/src/main/java/fishrungames/yelpmapapp/MapsActivity.kt @@ -27,11 +27,11 @@ import android.content.DialogInterface import android.support.v7.app.AlertDialog -class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, +open class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { - private var mMap: GoogleMap? = null + internal var mMap: GoogleMap? = null private var mLastLocation: Location? = null @@ -61,22 +61,20 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, override fun onMapReady(googleMap: GoogleMap) { // Add a marker in Sydney and move the camera - val sydney = LatLng(-34.0, 151.0) - googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney")) - googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney)) + //val sydney = LatLng(-34.0, 151.0) + //googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney")) + //googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney)) - if (ContextCompat.checkSelfPermission(this, - Manifest.permission.ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED) { - //Location Permission already granted - buildGoogleApiClient() - googleMap.setMyLocationEnabled(true) - } else { - //Request Location Permission - checkLocationPermission() - } + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + //Location Permission already granted + buildGoogleApiClient() + googleMap.isMyLocationEnabled = true + } else { + //Request Location Permission + checkLocationPermission() + } mMap = googleMap @@ -85,11 +83,13 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, override fun onConnected(bundle: Bundle?) { val locationRequest = LocationRequest() - locationRequest.setInterval(1000) - locationRequest.setFastestInterval(1000) - locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) - if (ContextCompat.checkSelfPermission(this, - Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + + locationRequest.interval = 1000 + locationRequest.fastestInterval = 1000 + locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY + + + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this) } @@ -101,18 +101,14 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, override fun onConnectionFailed(connectionResult: ConnectionResult) {} override fun onLocationChanged(location: Location) { - mLastLocation = location - //Place current location marker - val latLng = LatLng(location.latitude, location.longitude) - /* - val markerOptions = MarkerOptions() - markerOptions.position(latLng) - markerOptions.title("Current Position") - markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)) - mCurrLocationMarker = mGoogleMap.addMarker(markerOptions)*/ + if (mLastLocation == null) { + val latLng = LatLng(location.latitude, location.longitude) - mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11f)) + mLastLocation = location + + mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11f)) + } } @@ -187,6 +183,3 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, } } -class LocationRequest { - -} diff --git a/app/src/main/java/fishrungames/yelpmapapp/YelpInfoWindowProvider.kt b/app/src/main/java/fishrungames/yelpmapapp/YelpInfoWindowProvider.kt new file mode 100755 index 0000000..678523e --- /dev/null +++ b/app/src/main/java/fishrungames/yelpmapapp/YelpInfoWindowProvider.kt @@ -0,0 +1,32 @@ +package fishrungames.yelpmapapp + +import android.app.Activity +import android.content.Context +import android.view.View +import com.google.android.gms.maps.model.Marker +import android.widget.TextView +import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter + + + +/** + * Created by mephi on 10.06.2017. + */ + +internal class MyInfoWindowAdapter(val activity: Activity) : InfoWindowAdapter { + + private val myContentsView: View = activity.layoutInflater.inflate(R.layout.yelp_info_contents, null) + + override fun getInfoContents(marker: Marker): View { + + //myContentsView.findViewById(R.id.title) = marker.title + //myContentsView.findViewById(R.id.snippet).text = marker.snippet + + return myContentsView + } + + override fun getInfoWindow(marker: Marker): View? { + return null + } + +} \ No newline at end of file diff --git a/app/src/main/java/fishrungames/yelpmapapp/YelpMapActivity.kt b/app/src/main/java/fishrungames/yelpmapapp/YelpMapActivity.kt new file mode 100755 index 0000000..cba73f2 --- /dev/null +++ b/app/src/main/java/fishrungames/yelpmapapp/YelpMapActivity.kt @@ -0,0 +1,141 @@ +package fishrungames.yelpmapapp + +import android.location.Location +import android.os.Handler +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.model.Marker +import com.google.android.gms.maps.model.BitmapDescriptorFactory +import com.google.android.gms.maps.model.MarkerOptions +import com.google.android.gms.maps.model.LatLng +import java.util.* +import com.google.maps.android.clustering.ClusterManager +import com.google.android.gms.maps.CameraUpdateFactory + + + + + + +/** + * Created by mephi on 09.06.2017. + */ + + +class YelpMapActivity : MapsActivity() +{ + + val handler = Handler() + + val dataProvider = DataProvider(this, this::handleMarkersUpdated) + + private var mClusterManager: ClusterManager? = null + + val markerMap = mutableMapOf() + + var latestRequestDate : Date? = null + + var requestScheduled : Boolean = false + + override fun onMapReady(googleMap: GoogleMap) { + super.onMapReady(googleMap) + + googleMap.setOnCameraMoveListener { + + tryRequestData(googleMap.cameraPosition.target.latitude, googleMap.cameraPosition.target.longitude) + + } + + setUpClusterer(googleMap) + } + + + override fun onLocationChanged(location: Location) { + super.onLocationChanged(location) + tryRequestData(location.latitude, location.longitude) + } + + fun handleMarkersUpdated(newMarkerMap: Map) + { + if (mClusterManager == null) + { + return + } + + val clusterManager = mClusterManager!! + + for (key in newMarkerMap.keys) + { + + + if (!markerMap.containsKey(key)) + { + val mapMarkerRecord = newMarkerMap[key] as MapMarkerRecord + + val mapMarkerClusterItem = MapMarkerClusterItem(mapMarkerRecord) + + clusterManager.addItem(mapMarkerClusterItem) + + markerMap[key] = mapMarkerClusterItem + + } + } + } + + + + fun tryRequestData(lat : Double, lon : Double) { + + val requestLimitInMs = 2000L + + val newDate = Date() + + if (latestRequestDate == null) + { + innerRequestData(lat, lon) + } + else { + if (!requestScheduled) { + + requestScheduled = true + + val timeDiffMs = newDate.time - latestRequestDate!!.time + + if (timeDiffMs > requestLimitInMs) { + innerRequestData(lat, lon) + } else { + + handler.postDelayed({ innerRequestData(lat, lon) }, requestLimitInMs - timeDiffMs) + + } + } + } + } + + fun innerRequestData(lat : Double, lon : Double) + { + val radius = 2000 + + latestRequestDate = Date() + + dataProvider.requestData(lat, lon, radius) + + requestScheduled = false + + } + + + private fun setUpClusterer(googleMap: GoogleMap) { + + // Initialize the manager with the context and the map. + // (Activity extends context, so we can pass 'this' in the constructor.) + mClusterManager = ClusterManager(this, googleMap) + + // Point the map's listeners at the listeners implemented by the cluster + // manager. + googleMap.setOnCameraIdleListener(mClusterManager) + googleMap.setOnMarkerClickListener(mClusterManager) + + } + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_maps.xml b/app/src/main/res/layout/activity_maps.xml index 5c09f25..569b781 100755 --- a/app/src/main/res/layout/activity_maps.xml +++ b/app/src/main/res/layout/activity_maps.xml @@ -5,4 +5,4 @@ android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="fishrungames.yelpmapapp.MapsActivity" /> + tools:context="fishrungames.yelpmapapp.YelpMapActivity" /> diff --git a/app/src/main/res/layout/yelp_info_contents.xml b/app/src/main/res/layout/yelp_info_contents.xml new file mode 100755 index 0000000..fc0ef08 --- /dev/null +++ b/app/src/main/res/layout/yelp_info_contents.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 343cb05..00c45f1 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ YelpMapApp - Map + Yelp Map App