DT @12.11.2015: Maps: Clustering und HeatMap implemented

This commit is contained in:
Dennis Thießen
2015-11-12 20:58:28 +01:00
parent 49ba686b3f
commit 380eefef21
10 changed files with 215 additions and 88 deletions

View File

@@ -98,6 +98,7 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-wallet/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-wearable/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services/7.5.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.maps.android/android-maps-utils/0.3.4/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.twitter.sdk.android/twitter-core/1.4.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/io.fabric.sdk.android/fabric/1.3.4/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
@@ -146,6 +147,7 @@
<orderEntry type="library" exported="" name="facebook-android-sdk-4.1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-22.2.0" level="project" />
<orderEntry type="library" exported="" name="play-services-cast-7.5.0" level="project" />
<orderEntry type="library" exported="" name="android-maps-utils-0.3.4" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-22.2.0" level="project" />
<orderEntry type="library" exported="" name="play-services-ads-7.5.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />

View File

@@ -46,4 +46,5 @@ dependencies {
transitive = true;
}
compile 'com.beardedhen:androidbootstrap:2.0.0'
compile 'com.google.maps.android:android-maps-utils:0.3+'
}

View File

@@ -5,9 +5,6 @@ import android.app.SearchableInfo;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
@@ -26,40 +23,52 @@ import com.google.android.gms.maps.CameraUpdate;
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.Circle;
import com.google.android.gms.maps.model.CircleOptions;
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 com.google.android.gms.maps.model.TileOverlay;
import com.google.android.gms.maps.model.TileOverlayOptions;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.heatmaps.HeatmapTileProvider;
import org.deke.risk.riskahead.helper.AppClusterItem;
import org.deke.risk.riskahead.helper.AppConfig;
import org.deke.risk.riskahead.helper.AppController;
import org.deke.risk.riskahead.helper.BaseActivity;
import org.deke.risk.riskahead.helper.OwnIconRendered;
import org.deke.risk.riskahead.helper.PlaceProvider;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCallbacks<Cursor>, GoogleMap.OnInfoWindowClickListener {
public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCallbacks<Cursor>, ClusterManager.OnClusterItemInfoWindowClickListener<AppClusterItem>{
private final static String mActivityTitle = "Risk Map";
private static final String TAG = MapsActivity.class.getSimpleName();
private static GoogleMap mMap;
Marker mMarker;
HashMap<String, String> markerIDs = new HashMap<>();
ArrayList<AppClusterItem> myMarkers = new ArrayList<AppClusterItem>();
private float previousZoomLevel = -1.0f;
private boolean isZooming = false;
private LatLng myLocation;
private LatLng markedLocation;
private List<LatLng> mPositionList = new ArrayList<>();
ClusterManager<AppClusterItem> mClusterManager;
private static final int DEFAULT_ZOOM_LEVEL = 14;
private static final int THRESHOLD_ZOOM_LEVEL = 6;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -67,11 +76,11 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.frag_maps_map)).getMap();
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.setMyLocationEnabled(true);
handleIntent(getIntent());
findViewById(R.id.btn_maps_confirm_position).setVisibility(View.GONE);
mMap.setOnInfoWindowClickListener(this);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
@@ -81,7 +90,7 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
}
markedLocation = point;
mMarker = mMap.addMarker(new MarkerOptions().position(point));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, 12.0f));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, DEFAULT_ZOOM_LEVEL));
findViewById(R.id.btn_maps_confirm_position).setVisibility(View.VISIBLE);
findViewById(R.id.btn_maps_confirm_position).setOnClickListener(new View.OnClickListener() {
@@ -93,13 +102,62 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
}
});
//setUpMap();
setUpClustering();
}
public GoogleMap.OnCameraChangeListener getCameraChangeListener()
{
return new GoogleMap.OnCameraChangeListener()
{
@Override
public void onCameraChange(CameraPosition position)
{
mClusterManager.onCameraChange(position);
Log.d("Zoom", "Zoom: " + position.zoom);
if(previousZoomLevel != position.zoom)
{
if(previousZoomLevel < THRESHOLD_ZOOM_LEVEL && position.zoom >= THRESHOLD_ZOOM_LEVEL){
mClusterManager.addItems(myMarkers);
}else if(previousZoomLevel > THRESHOLD_ZOOM_LEVEL && position.zoom <= THRESHOLD_ZOOM_LEVEL){
mClusterManager.clearItems();
}
}
previousZoomLevel = position.zoom;
}
};
}
private void setUpClustering() {
mClusterManager = new ClusterManager<AppClusterItem>(this, mMap);
//mMap.setOnCameraChangeListener(mClusterManager);
mMap.setOnCameraChangeListener(getCameraChangeListener());
mMap.setOnMarkerClickListener(mClusterManager);
mClusterManager.setRenderer(new OwnIconRendered(this, mMap, mClusterManager));
mMap.setOnInfoWindowClickListener(mClusterManager);
mClusterManager.setOnClusterItemInfoWindowClickListener(this);
addClusterMarkers(mClusterManager);
}
private void addClusterMarkers(ClusterManager<AppClusterItem> mClusterManager) {
String tag_string_req = "getincidentswithposition";
StringRequest strReq = getStringRequestGetAllIncidentsWithPosition();
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
private void addHeatMap() {
HeatmapTileProvider mProvider = new HeatmapTileProvider.Builder()
.data(mPositionList)
.radius(50)
.build();
TileOverlay mOverlay = mMap.addTileOverlay(new TileOverlayOptions().tileProvider(mProvider));
}
private void handleIntent(Intent intent){
if(Intent.ACTION_SEARCH.equals(intent.getAction()))
{
@@ -150,7 +208,7 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
position = new LatLng(Double.parseDouble(c.getString(1)),Double.parseDouble(c.getString(2)));
markerOptions.position(position);
markerOptions.title(c.getString(0));
mMarker = mMap.addMarker(markerOptions);
//mMarker = mMap.addMarker(markerOptions);
}
if(position!=null){
CameraUpdate cameraPosition = CameraUpdateFactory.newLatLng(position);
@@ -196,18 +254,6 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
return true;
}
private void setUpMap() {
// For showing a move to my loction button
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(true);
// For dropping a marker at a point on the Map
mMap.addMarker(new MarkerOptions().position(myLocation).title("My Home").snippet("Home Address"));
// For zooming automatically to the Dropped PIN Location
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(myLocation, 12.0f));
}
@Override
public void onDestroy() {
super.onDestroy();
@@ -239,52 +285,38 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("error");
// Check for error node in json
if (!error) {
JSONArray incidents = jObj.getJSONArray("message");
for(int i=0;i<incidents.length();i++){
JSONObject incident = incidents.getJSONObject(i);
LatLng pos = new LatLng(Double.parseDouble(incident.getString("latitude")),Double.parseDouble(incident.getString("longitude")));
Log.d(TAG, "Adding marker with position: " + pos.latitude +" : "+ pos.longitude);
Log.d(TAG, "Adding marker with position: " + pos.latitude + " : " + pos.longitude);
mMarker = mMap.addMarker(new MarkerOptions()
.position(pos)
.title(incident.getString("text_short"))
.snippet("Crime Category:" + incident.getString("cat_name")));
switch (incident.getInt("fid_category")) {
case 1:
mMarker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
break;
case 2:
mMarker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
break;
case 3:
mMarker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
break;
}
markerIDs.put(mMarker.getId(), incident.getString("uid"));
AppClusterItem offsetItem = new AppClusterItem(incident,pos);
myMarkers.add(offsetItem);
//mClusterManager.addItem(offsetItem);
mPositionList.add(pos);
/*
CircleOptions circleOptions = new CircleOptions()
.center(pos)
.strokeColor(Color.BLACK)
.strokeWidth(2)
.strokeWidth(0)
.fillColor(Color.parseColor("#"+incident.getString("color")))
.radius(incident.getInt("radius")); // In meters
Circle circle = mMap.addCircle(circleOptions);
*/
}
addHeatMap();
} else {
// Error in login. Get the error message
String errorMsg = jObj.getString("error_msg");
Toast.makeText(getApplicationContext(), errorMsg, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// JSON error
e.printStackTrace();
}
@@ -317,7 +349,7 @@ public class MapsActivity extends BaseActivity implements LoaderManager.LoaderCa
@Override
public void onInfoWindowClick(Marker marker) {
gotoViewReportActivity(markerIDs.get(marker.getId()));
public void onClusterItemInfoWindowClick(AppClusterItem appClusterItem) {
gotoViewReportActivity(appClusterItem.getID());
}
}

View File

@@ -0,0 +1,90 @@
package org.deke.risk.riskahead.helper;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.clustering.ClusterItem;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by Dennis on 12.11.2015.
*/
public class AppClusterItem implements ClusterItem {
private LatLng mPosition;
private String mID;
private String mTitle;
private String mDescription;
private String mFidUser;
private String mFidCategory;
private String mHappenedAt;
private String mCreatedAt;
private String mUpdatedAt;
private String mRadius;
private String mCatName;
private String mCatDescription;
private String mColor;
private BitmapDescriptor icon;
public AppClusterItem(JSONObject mIncident, LatLng pos) {
try {
this.mID = mIncident.getString("uid");
this.mTitle = mIncident.getString("text_short");
this.mDescription = mIncident.getString("text_long");
this.mFidUser = mIncident.getString("fid_user");
this.mFidCategory = mIncident.getString("fid_category");
this.mHappenedAt = mIncident.getString("happened_at");
this.mCreatedAt = mIncident.getString("created_at");
this.mUpdatedAt = mIncident.getString("updated_at");
this.mRadius = mIncident.getString("radius");
this.mCatName = mIncident.getString("cat_name");
this.mCatDescription = mIncident.getString("cat_description");
this.mColor = mIncident.getString("color");
this.mPosition = pos;
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public LatLng getPosition() {
return mPosition;
}
public BitmapDescriptor getIcon() {
BitmapDescriptor mIcon;
switch (Integer.valueOf(this.mFidCategory)) {
case 1:
mIcon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED);
break;
case 2:
mIcon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN);
break;
case 3:
mIcon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE);
break;
default:
mIcon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW);
break;
}
return mIcon;
}
public String getSnippet() {
return this.mDescription;
}
public String getTitle() {
return this.mTitle;
}
public String getID() {
return mID;
}
}

View File

@@ -1,9 +1,7 @@
package org.deke.risk.riskahead.helper;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
@@ -20,13 +18,6 @@ import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.beardedhen.androidbootstrap.TypefaceProvider;
import com.google.android.gms.maps.model.LatLng;
import org.deke.risk.riskahead.LoginActivity;
import org.deke.risk.riskahead.MainActivity;
import org.deke.risk.riskahead.MapsActivity;
@@ -37,14 +28,8 @@ import org.deke.risk.riskahead.ReportlistActivity;
import org.deke.risk.riskahead.SettingsActivity;
import org.deke.risk.riskahead.SubscriptionsActivity;
import org.deke.risk.riskahead.ViewReportActivity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public abstract class BaseActivity extends AppCompatActivity {
@@ -54,10 +39,8 @@ public abstract class BaseActivity extends AppCompatActivity {
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ArrayAdapter<String> mAdapter;
private ShareActionProvider mShareActionProvider;
private DrawerItemCustomAdapter adapter;
private String[] mNavigationDrawerItemTitles;
private DrawerItemCustomAdapter mCustomDrawerAdapter;
public SessionManager session;
public HashMap<String, String> user;
@@ -92,7 +75,7 @@ public abstract class BaseActivity extends AppCompatActivity {
drawerItem[5] = new ObjectDrawerItem(R.drawable.ic_action_important, "Subscriptions");
drawerItem[6] = new ObjectDrawerItem(R.drawable.ic_action_back, "Logout");
adapter = new DrawerItemCustomAdapter(this, R.layout.listview_item_row, drawerItem);
mCustomDrawerAdapter = new DrawerItemCustomAdapter(this, R.layout.listview_item_row, drawerItem);
mDrawerList = (ListView)findViewById(R.id.navList);
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
@@ -112,7 +95,6 @@ public abstract class BaseActivity extends AppCompatActivity {
public void logout() {
session.setLogin(false);
// Launching the login activity
Intent intent = new Intent(this, LoginActivity.class);
intent.putExtra(EXTRA_MESSAGE, "login");
startActivity(intent);
@@ -124,17 +106,14 @@ public abstract class BaseActivity extends AppCompatActivity {
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_common, menu);
// Access the Share Item defined in menu XML
/*
MenuItem shareItem = menu.findItem(R.id.menu_item_share);
// Access the object responsible for
// putting together the sharing submenu
if (shareItem != null) {
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);
}
// Create an Intent to share your content
setShareIntent();
*/
getMenuInflater().inflate(R.menu.menu_login, menu);
return true;
@@ -163,9 +142,7 @@ public abstract class BaseActivity extends AppCompatActivity {
}
private void addDrawerItems() {
String[] osArray = { "Start", "Report", "Incident Map", "User Statistics", "Account Settings", "Subscriptions", "Logout" };
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, osArray);
mDrawerList.setAdapter(adapter);
mDrawerList.setAdapter(mCustomDrawerAdapter);
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override

View File

@@ -30,7 +30,6 @@ public class DrawerItemCustomAdapter extends ArrayAdapter<ObjectDrawerItem> {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItem = convertView;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();

View File

@@ -7,9 +7,7 @@ public class ObjectDrawerItem {
public int icon;
public String name;
// Constructor.
public ObjectDrawerItem(int icon, String name) {
this.icon = icon;
this.name = name;
}

View File

@@ -0,0 +1,29 @@
package org.deke.risk.riskahead.helper;
import android.content.Context;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.clustering.view.ClusterRenderer;
import com.google.maps.android.clustering.view.DefaultClusterRenderer;
import org.deke.risk.riskahead.MapsActivity;
/**
* Created by Dennis on 12.11.2015.
*/
public class OwnIconRendered extends DefaultClusterRenderer<AppClusterItem> {
public OwnIconRendered(Context context, GoogleMap map,ClusterManager<AppClusterItem> clusterManager) {
super(context, map, clusterManager);
}
@Override
protected void onBeforeClusterItemRendered(AppClusterItem item, MarkerOptions markerOptions) {
markerOptions.icon(item.getIcon());
markerOptions.snippet(item.getSnippet());
markerOptions.title(item.getTitle());
super.onBeforeClusterItemRendered(item, markerOptions);
}
}

View File

@@ -1,10 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:omgandroid="http://schemas.android.com/apk/res-auto">
<item
<!-- <item
android:id="@+id/menu_item_share"
android:title="Share"
omgandroid:showAsAction="ifRoom"
omgandroid:actionProviderClass= "android.support.v7.widget.ShareActionProvider" />
omgandroid:actionProviderClass= "android.support.v7.widget.ShareActionProvider" />-->
</menu>

View File

@@ -11,4 +11,3 @@ buildscript {
classpath 'io.fabric.tools:gradle:1.+'
}
}