Im developing an app using Google Maps v2 for Android and I managed to put a custom icon to the user's position but I can't remove the default one, so it overlays my custom icon like in the image:
(It is that big just for now :p )
My code is like:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
map.setMyLocationEnabled(true);
map.setOnMyLocationChangeListener(new OnMyLocationChangeListener() {
#Override
public void onMyLocationChange(Location location) {
if (location == null)
return;
mPositionMarker = map.addMarker(new MarkerOptions()
.flat(true)
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.logop1))
.anchor(0.5f, 1f)
.position(new LatLng(location.getLatitude(), location.getLongitude())));
}
});
}
So:
1) Is there a way to remove the default blue dot of user's current location?
2) Will the user location be updated when I move in the "real world" (I cant test it for conectivity reasons) or do I have to write/override a method to update users position?
Thanks in advance
You will have to stop using GoogleMap.setMyLocationEnabled and write a bit more code, including having your own LocationClient and adding Circle for accuracy.
You have to do that on your own.
- set to false gmaps.getUiSettings().setMyLocationButtonEnabled(false);
create your own location button
if you get your current location, set a marker with your icon on that
if you click on your location button, move the camera and center it to the map
That will remove the blue dot
map.setMyLocationEnabled(true); remove line
Thanks joao2fast4u (lol) and ṁᾶƔƏň ツ. I followed your recomendations and I managed to make it work. Since I didn't see any answer concrete to this problem I'm posting my solution here:
package com.onsoftwares.ufvquest;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
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.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapActivity extends ActionBarActivity implements LocationListener, GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener {
private GoogleMap map;
private Marker mPositionMarker;
private LocationClient mLocationClient;
private LocationRequest mLocationRequest;
private LatLng mLatLng;
private boolean mUpdatesRequested = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
mLocationClient = new LocationClient(this, this, this);
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the interval ceiling to one minute
mLocationRequest.setFastestInterval(1000);
// Note that location updates are off until the user turns them on
mUpdatesRequested = false;
}
#Override
protected void onStart() {
super.onStart();
mLocationClient.connect();
};
#Override
protected void onStop() {
if (mLocationClient.isConnected()) {
mLocationClient.removeLocationUpdates(this);
mLocationClient.disconnect();
}
super.onStop();
};
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnected(Bundle arg0) {
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
}
#Override
public void onLocationChanged(Location location) {
// Get the current location
Location currentLocation = mLocationClient.getLastLocation();
// Display the current location in the UI
if (currentLocation != null) {
LatLng currentLatLng = new LatLng (currentLocation.getLatitude(), currentLocation.getLongitude());
if (mPositionMarker == null) {
mPositionMarker = map.addMarker(new MarkerOptions()
.position(currentLatLng)
.title("Eu")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.male_user_marker)));
map.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15));
} else
mPositionMarker.setPosition(currentLatLng);
}
}
}
Related
I need your help.
How can I move the camera on my current position, immediately when I open the app?
I have a button which works (if I click it, it move the camera on my current position), but when I open the app, the camera is set on the middle of the ocean.
I want to open the app and the camera is already set on my current position.
This is my code:
MapsActivity.java
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.common.api.GoogleApi;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
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.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleMap mMap;
private GoogleApiClient googleApiClient;
private LocationRequest locationRequest;
private Location lastLocation;
private Marker currentUserLocationMarker;
private static final int Request_User_Location_Code = 99;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
checkUserLocationPermission();
}
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
/*disabling toolbar (it is used to continue using this app without having to
use the official google maps app)*/
mMap.getUiSettings().setMapToolbarEnabled(false);
}
public boolean checkUserLocationPermission(){
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, Request_User_Location_Code );
}
else{
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, Request_User_Location_Code );
}
return false;
}
else{
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode){
case Request_User_Location_Code:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
if(googleApiClient == null){
buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
}
else{
Toast.makeText(this, "Permesso vietato", Toast.LENGTH_SHORT).show();
}
return;
}
}
protected synchronized void buildGoogleApiClient(){
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
lastLocation = location;
if(currentUserLocationMarker != null){
currentUserLocationMarker.remove();
}
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Posizione corrente");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
currentUserLocationMarker = mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomBy(11));
if (googleApiClient != null){
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
locationRequest = new LocationRequest();
locationRequest.setInterval(1100);
locationRequest.setFastestInterval(1100);
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
activity_maps.xml:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity"
class="com.google.android.gms.maps.SupportMapFragment"/>
Already add this in my AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Thanks for your help.
So you have done almost all the work already. You just need to go one step further.
First to understand, setMyLocationEnabled when set to true adds that location compass button on the map. This is what you click to find your current location. Good start.
You also need to set the camera to your current location when you initialize the map.
if(locationPermissionGranted){
Task<Location> locationResult = fusedLocationProviderClient.getLastLocation();
locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
if(task.isSuccessful()){
// Set the maps camera to current location
lastKnownLocation = task.getResult();
map.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()), 12));
}
else{
Log.d(TAG, "Current location is null");
Log.e(TAG,"Exception: %s", task.getException());
map.moveCamera(CameraUpdateFactory.newLatLngZoom(defaultLocation, 12));
map.getUiSettings().setMyLocationButtonEnabled(false);
}
}
});
}
Try this. First make sure you have location permissions granted. Then try and find the last known location. (If you are using an emulator try opening Google Maps before trying this code. The location services on an emulator have never been initiated). It will try and grab your current location. If success it moves the camera to that location, if failed I have set a default location for the map to move to instead of opening in the ocean.
private LatLng defaultLocation = new LatLng(41.651031, -83.541939);
Hope this helps.
I think, I solved in this way.
I have modified my onMapReady:
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
mMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {
#Override
public void onMyLocationChange(Location arg0) {
float zoomLevel = 15.0f;
LatLng latLng = new LatLng(arg0.getLatitude(), arg0.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoomLevel));
}
});
}
/*disabling toolbar (it is used to continue using this app without having to
use the official google maps app)*/
mMap.getUiSettings().setMapToolbarEnabled(false);
Then, when I open my app, the camera is set on my current location.
Thanks a lot.
[Prerequisite] - Make sure you have location permission granted and location services is turned on.
public void onMapReady(GoogleMap googleMap){
mMap = googleMap;
// You can register for Location Change Once the location is updated,
// Fetch lat, lng from it. Once you have lat,lng convert it into `LatLng`
LatLng currLatLng = fetchedFromAPI();
CameraPosition newPos =
new CameraPosition.Builder()
.target(currLatLng)
.build();
if (showAnimation){
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(newPos));
}else{
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(newPos));
}
}
Instead of LocationManager, I have use LocationServices method to get current gps location and location updates.
this is the code:
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();//PRIORITY_BALANCED_POWER_ACCURACY
mLocationRequest.setInterval(1000*30*1);
mLocationRequest.setFastestInterval(1000*30*1);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest,this);
}
}
public void onLocationChanged(Location location) { mLastLocation = location;
if (mCurrLocationMarker != null)
{
mCurrLocationMarker.remove();
}
//Place current location marker
latLng = new LatLng(location.getLatitude(), location.getLongitude());
lat= location.getLatitude();
log=location.getLongitude();
trim_check_location_change(lat,log);
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title(""+s);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
CurrentLocation = latLng;
}
As I move from from one place to another, blue marker moves accordingly.
however onlocationchanged method never gets called.
I've developed fused location api demo application and utility pack here.
General Utilities
Try it if useful for you. To get location using fused location api, you just have to write following snippet...
new LocationHandler(this)
.setLocationListener(new LocationListener() {
#Override
public void onLocationChanged(Location location) {
// Get the best known location
}
}).start();
And if you want to customise it, simply find documentation here...
https://github.com/abhishek-tm/general-utilities-android/wiki/Location-Handler
Update
I've written a sample code according to your need, try this one...
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import in.teramatrix.utilities.service.LocationHandler;
import in.teramatrix.utilities.util.MapUtils;
/**
* Lets see how to use utilities module by implementing location listener.
*
* #author Khan
*/
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, LocationListener {
private GoogleMap map;
private Marker marker;
private LocationHandler locationHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Obtaining an instance of map
FragmentManager manager = getSupportFragmentManager();
SupportMapFragment mapFragment = (SupportMapFragment) manager.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
this.locationHandler = new LocationHandler(this)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(5000)
.setFastestInterval(10000)
.setLocationListener(this);
}
#Override
public void onMapReady(GoogleMap map) {
this.map = map;
this.locationHandler.start();
}
#Override
public void onLocationChanged(Location location) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
if (marker == null) {
marker = MapUtils.addMarker(map, latLng, R.drawable.ic_current_location);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 14), 500, null);
} else {
marker.setPosition(latLng);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (locationHandler != null) {
locationHandler.stop();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LocationHandler.REQUEST_LOCATION) {
locationHandler.start();
}
}
}
Hope it will help you.
I'm using Google Maps API.
What I want is when I move into some specific location and there is a circle I already have draw on the map, it will then go to another Activity.
So it was like :
my position is a = (X,Y)
Circle position is b = (X,Y) radius = 10
When I'm inside b radius it will go to another Activity or do something.
Any ideas ?
I'm already using distanceTo(), but still haven't succeeded.
Edit: Here is updated code that still is not working for me:
public void onLocationChanged(Location location)
{
float [] distance = new float[];
Location.distanceBetween(location.getLatitude(),location.getLongitude(),-6.xxxxxxx,106.xxxxxxx,distance);
if (distance[0] < 50)
{
Intent i = new Intent(student_activity.this,indoor.class);
student_activity.this,startActivity(i);
}
}
This method setUpMapIfNeeded() is called in onCreate method :
public void circle()
{
Circle circle = mMap.addCircle (new CircleOptions()
.center(new LatLng(-6.xxxxxxx,106.xxxxxxx))
.radius(50)
.strokeColor(Color.RED)
.strokeWidth(1)
.fillColor(Color.RED)
}
You could use geofencing, but if you are simply trying to determine if your current location is within a circle drawn on a map, you could use this technique.
Simply compare the distance from the current location to the center of the circle, and check if the distance is less than the radius.
I answered a similar question here, where you can see more info, and screenshot examples.
Note that the code below uses the depricated onMyLocationChangeListener, but you could use any type of location callback to do this, including FusedLocationProviderApi.
googleMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {
#Override
public void onMyLocationChange(Location location) {
float[] distance = new float[2];
Location.distanceBetween( location.getLatitude(), location.getLongitude(),
mCircle.getCenter().latitude, mCircle.getCenter().longitude, distance);
if( distance[0] < mCircle.getRadius() ){
//current location is within circle
//start new activity
Intent i = new Intent(ThisActivity.this, OtherActivity.class);
ThisActivity.this.startActivity(i);
}
}
});
Edit: Here is a fully working and tested class that uses the FusedLocationApi to get the current location:
import android.content.Intent;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
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.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends ActionBarActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleMap mMap;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Circle mCircle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
buildGoogleApiClient();
mGoogleApiClient.connect();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
#Override
protected void onPause(){
super.onPause();
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
protected synchronized void buildGoogleApiClient() {
Toast.makeText(this,"buildGoogleApiClient",Toast.LENGTH_SHORT).show();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public void onConnected(Bundle bundle) {
Toast.makeText(this,"onConnected", Toast.LENGTH_SHORT).show();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10);
mLocationRequest.setFastestInterval(10);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(0.1F);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.getUiSettings().setMapToolbarEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.setMyLocationEnabled(true);
circle();
}
public void circle()
{
double radiusInMeters = 50.0;
int strokeColor = 0xffff0000; //red outline
int shadeColor = 0x44ff0000; //opaque red fill
mCircle = mMap.addCircle (new CircleOptions()
.center(new LatLng(37.9614, -122.105))
.radius(radiusInMeters)
.fillColor(shadeColor)
.strokeColor(strokeColor)
.strokeWidth(1));
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();
}
#Override
public void onLocationChanged(Location location) {
Log.d("locationtesting", "lat: " + location.getLatitude() + " lon: " + location.getLongitude());
Toast.makeText(this,"Location Changed",Toast.LENGTH_SHORT).show();
float[] distance = new float[2];
Location.distanceBetween( location.getLatitude(), location.getLongitude(),
mCircle.getCenter().latitude, mCircle.getCenter().longitude, distance);
if( distance[0] < mCircle.getRadius() ){
//current location is within circle
//start new activity
Intent i = new Intent(this, OtherActivity.class);
startActivity(i);
}
}
}
Layout xml:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/map" tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment" />
Dependencies in build.gradle:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
compile 'com.google.android.gms:play-services:7.0.0'
}
First I did a test without the call to startActivity() just to make sure that my current location was within the circle. As you can see in the screenshot, it was:
Then, I added the call to startActivity() in the onLocationChanged() callback, and it launched OtherActivity immediately after launching the app.
It sounds like describing Google's geofences API
Geofencing tutorial
My app is currently using Maps by Google Play Services
speficying:
mMap.setMyLocationEnabled(true);
I realize each time I am displaying the map in my app:
the location is indicated on the map by a blue dot
a location icon is displaying in the top bar
if I go into Settings/Location of the phone, my app is reported as "High battery use"
However, I can see there are apps that use Maps and still show the location blue dot, but the location icon doesn't appear in top bar and their battery usage is low.
My app currently grants both permissions:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
My question is:
how can I show the location blue dot with low battery usage?
is it possible to specify the accuracy/battery usage by code?
UPDATE
Actually I realized that the way to do it is to use the GoogleApiClient's FusedLocationApi
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
I have configured the GoogleApiClient inside my Activity, calling:
GoogleApiClient.connect() on the Activity's start
GoogleApiClient.disconnect() on the Activity's stop
on the onConnected callback I set the criteria for the location updates: fastest interval of 1 minute with low power priority:
private static final LocationRequest REQUEST = LocationRequest.create()
.setFastestInterval(60000) // in milliseconds
.setInterval(180000) // in milliseconds
.setPriority(LocationRequest.PRIORITY_LOW_POWER);
#Override
public void onConnected(Bundle bundle) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}
I have tested that the GoogleApiClient connects correctly at start, but for some reasons whenever I visit the fragment with the embedded MapView, I still get the high battery use for my app on the Settings/Location screen!
It seems the MapView is ignoring these low power criterias!
FINALLY FOUND THE SOLUTION!!!
thanks to Tristan for his answer!
By default, GoogleMap uses its on location provider, which is not the Fused Location Provider. In order to use the Fused Location Provider (which allows you to control the location accuracy and power consumption) you need to explicitely set the map location source with GoogleMap.setLocationSource() (documentation)
I am reporting here a sample activity to do that:
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends FragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener,
LocationSource,
LocationListener,
OnMyLocationButtonClickListener,
OnMapReadyCallback {
private GoogleApiClient mGoogleApiClient;
private TextView mMessageView;
private OnLocationChangedListener mMapLocationListener = null;
// location accuracy settings
private static final LocationRequest REQUEST = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMessageView = (TextView) findViewById(R.id.message_text);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
protected void onResume() {
super.onResume();
mGoogleApiClient.connect();
}
#Override
public void onPause() {
super.onPause();
mGoogleApiClient.disconnect();
}
#Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
}
public void showMyLocation(View view) {
if (mGoogleApiClient.isConnected()) {
String msg = "Location = "
+ LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
}
/**
* Implementation of {#link LocationListener}.
*/
#Override
public void onLocationChanged(Location location) {
mMessageView.setText("Location = " + location);
if (mMapLocationListener != null) {
mMapLocationListener.onLocationChanged(location);
}
}
#Override
public void onConnected(Bundle connectionHint) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}
#Override
public void onConnectionSuspended(int cause) {
// Do nothing
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Do nothing
}
#Override
public boolean onMyLocationButtonClick() {
Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show();
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
return false;
}
#Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mMapLocationListener = onLocationChangedListener;
}
#Override
public void deactivate() {
mMapLocationListener = null;
}
}
You will want to make your activity (or better a separate object for this purpose) implement the LocationSource interface.
It is pretty simple you need to store the listener passed in the activate() method and call it when the location is updated and forget it when deactivate() is called. See this answer for an example, you will probably want to update it to use the FusedLocationProvider.
Once you have this set up you can pass your activity as the LocationSource for the map like so mMap.setLocationSource(this) (documentation).
This will stop the map from using its default LocationSource which uses the high battery use location services.
It's stated here that
FusedLocationProviderApi provides improved location finding and power usage and is used by the "My Location" blue dot.
So "My Location" dot on map is fed by FusedLocationProviderApi. And as you grant permission android.permission.ACCESS_FINE_LOCATION you allow FusedLocationProviderApi for your app to get data from GPS which may cause high battery use.
So add only android.permission.ACCESS_COARSE_LOCATION permission to manifest and Android should not blame you for battery usage.
You can do so by using Network provider classes
You can use below code
AppLocationService.java // Special for getting current location with low battery usage (same like Battery saver mode in nexus 5 ,5.0)
package coreclass;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
public class AppLocationService extends Service implements LocationListener {
protected LocationManager locationManager;
Location location;
private static final long MIN_DISTANCE_FOR_UPDATE = 10;
private static final long MIN_TIME_FOR_UPDATE = 1000 * 60 * 2;
public AppLocationService(Context context) {
locationManager = (LocationManager) context
.getSystemService(LOCATION_SERVICE);
}
public Location getLocation(String provider) {
if (locationManager.isProviderEnabled(provider)) {
locationManager.requestLocationUpdates(provider,
MIN_TIME_FOR_UPDATE, MIN_DISTANCE_FOR_UPDATE, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(provider);
return location;
}
}
return null;
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Usage of above class
MainActivity.java
AppLocationService appLocationService;
appLocationService = new AppLocationService(getActivity());
Location nwLocation = appLocationService.getLocation(LocationManager.NETWORK_PROVIDER);
if (nwLocation != null) {
Lat = nwLocation.getLatitude();
Longi = nwLocation.getLongitude();
}
In this way you can get the current location with GPS mode in high bettery usage mode, after you can set the blue dot or whatever you want
Hope it helps you and all
I try to make a location app based on Android Maps API v2. I add marker for my location point and a GroundOverlay circle for location accuracy. But GroundOverlay setPosition function sets slightly different. I can't find why.
package com.example.locator;
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.GroundOverlay;
import com.google.android.gms.maps.model.GroundOverlayOptions;
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 android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.content.Context;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
public class MainActivity extends FragmentActivity implements LocationListener
{
GoogleMap mMap;
Location lastLocation = null;
private LocationManager locationManager;
private String provider;
Marker curLoc = null;
GroundOverlay curLocCircle = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(22.375675950685434, 29.83346939086914), 13));
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
onLocationChanged(location);
} else {
//empty
}
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void onLocationChanged(Location location) {
if (location != null) {
if (null != curLoc) {
curLoc.remove();
}
if (null != curLocCircle) {
curLocCircle.remove();
}
LatLng loc = new LatLng(location.getLatitude(),location.getLongitude());
curLoc = mMap.addMarker(new MarkerOptions()
.position(loc)
.title("My location")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.location32)));
float accuracy = location.getAccuracy();
curLocCircle = mMap.addGroundOverlay(new GroundOverlayOptions()
.image(BitmapDescriptorFactory
.fromResource(R.drawable.location_circle))
.position(loc, accuracy)
.transparency(0)
);
curLocCircle.setPosition(loc);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(loc, 13));
}
}
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
When I pause app in debugger on line
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(loc, 13));
watches shows this data:
curLocCircle.getPosition() lat/lng: (22.397815012772206,29.954818561673164)
location.getLatitude() 22.397815
location.getLongitude() 29.9548184
loc lat/lng: (22.397815,29.9548184)
curLocCircle.getPosition() somehow shows incorrect location write after setPosition(loc);
Please help me with that.
The problem was in marker anchor.
Changed to:
curLoc = mMap.addMarker(new MarkerOptions()
.position(loc)
.anchor(0.5f, 0.5f)
.title("My location")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.location32)));
And everything is fine. I still don't get why location of GroundOverlay differs from defined location, but I don't care. It looks good.