I am trying to ask for user location permission but I need to set some kind of listener to the user response otherwise, I cant get the user location and the app crashes due to null pointer exception.
This are the functions I am using to get and set the location
private void setLocation() {
if (ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 44);
}
LocationManager locationManager;
locationManager = (LocationManager) getSystemService(ScoreActivity.this.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(locationManager.NETWORK_PROVIDER);
onLocationChanged(location);
}
#Override
public void onLocationChanged(#NonNull Location location) {
locationDetails=new LatLng(location.getLatitude(),location.getLongitude());
}
Related
In the documentation it has been stated clearly that LocationListener "Used for receiving notifications from FusedLocationProviderApi when the location has changed". On the other hand FusedLocationProviderApi has been marked as deprecated and they recommended to use FusedLocationProviderClient. Then, how to detect when a location has changed when using FusedLocationProviderClient?.
I need that because if I only use the requestLocationUpdate callback, it will update the value regardless of whether the location value changes or not.
I only need changes in location values. That way, it won't waste if I update the location value to the database. In short, updating the location values only that location changes. instead of updating location values based on time span.
The Code:
private void createLocationCallback() {
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
//every 5 seconds
mLastLocation = locationResult.getLastLocation();
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
updateUI();//need onLocationChanged
}
};
}
private void startLocationUpdates(){
Log.e(TAG, "startLocationUpdate");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_FINE_LOCATION);
}
return;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest,mLocationCallback, Looper.myLooper());
}
In your LocationRequest, you can use setSmallestDisplacement.
Example
locationRequest.setSmallestDisplacement(10) // 10 meters. location callback only fired when location change more than 10 metter
Another thing is the location accuracy can not 100% so sometime you put don't move the phone but location still change.
It is OK when I open the GPS long times, I can get my current location, but when I turn off and then turn on the GPS, it returns null as the current location. I need to refresh or reinstall the app to make the current location work. Is it possible to get the location after a few seconds of turning on the GPS?
Here is my code:
client = LocationServices.getFusedLocationProviderClient(this);
LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
finish();
} else {
if (ActivityCompat.checkSelfPermission(MapsActivity.this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
return;
}
client.getLastLocation().addOnSuccessListener(MapsActivity.this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location!= null){
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
});
}
I found out that I need to use requestsLoctionUpdates, but I cannot find any tutorial that explains me how to do it in the new version of android studio (Location : 11.8.0). Can anyone can tell me how to use this code?
I am starting to learn about the runtime permissions. I have a map and I made a permission. If user allows fine location - map zooms to his current location, and if he doesn't allow it, the map stays in the place. What I want to do instead of map staying in the place is this: if the user doesn't allow permission for accessing his location, map should zoom in to my custom location (Greenwich).
My maps fragment:
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) {
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_LOCATION_REQUEST_CODE);
}
return;
}
mMap.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
// if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION)
// == PackageManager.PERMISSION_GRANTED) {
// mMap.setMyLocationEnabled(true);
// } else {
// // Show rationale and request permission.
// }
//Disable Map Toolbar:
mMap.getUiSettings().setMapToolbarEnabled(false);
// Get the name of the best provider and current location
String provider = null;
if (locationManager != null) {
provider = locationManager.getBestProvider(criteria, true);
}
// Get current location
Location myLocation = null;
if (locationManager != null) {
myLocation = locationManager.getLastKnownLocation(provider);
}
// Set default latitude and longitude to Greenwich
double latitude = 51.4825766;
double longitude = -0.0076589;
// Get latitude and longitude of the current location and a LatLng object
if (myLocation != null) {
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
}
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(latitude, longitude)).zoom(14).build();
mMap.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
}
You can zoom to location manually with this code :
CameraUpdate center=CameraUpdateFactory.newLatLng(new LatLng(latitude,
longitude));
CameraUpdate zoom=CameraUpdateFactory.zoomTo(15);
map.moveCamera(center);
map.animateCamera(zoom);
Couldn't find solution so I put the permission inside the parent activity. I think it is a known bug.
I just want to get user's postcode once. I am looking to start my app, check the user's current position once and stop checking. In the event I am unable to get it due to no connection, then I want to just use last known position provided it exists. Can I get some advice on this please.
My following code keeps showing null for last known position since I don't have one. And I do not want to look for location change. Irregardless of whether I move or not, check for position on app start and stop checking after.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
provider = locationManager.getBestProvider(new Criteria(), false);
Location location;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
1);
return;
}
location = locationManager.getLastKnownLocation(provider); // this is null and not ideal. I want current position.
Log.i("lat", String.valueOf(location.getLatitude()));
Log.i("lng", String.valueOf(location.getLongitude()));
getPostCode(location.getLatitude(), location.getLongitude());
}
private void getPostCode(double lat, double lng){
Geocoder geoCoder = new Geocoder(getApplicationContext(), Locale.getDefault());
List<Address> address = null;
try {
address = geoCoder.getFromLocation(lat, lng, 1);
} catch (IOException e) {
e.printStackTrace();
}
if (address != null) {
if (address.size() > 0) {
String postCode = address.get(0).getPostalCode();
Log.i("postcode", postCode);
}
}
}
I have implemented the Google Maps API v2 in my Android app. I add a marker and zoom to level 14 when I open the activity containing the map fragment.
Here is how I add/update the marker:
private void updateMarker() {
if(marker != null){
marker.remove();
}
LatLng latlng = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude));
marker = mMap.addMarker(new MarkerOptions().position(latlng).title(username));
marker.setIcon((BitmapDescriptorFactory.fromResource(R.drawable.marker)));
mMap.moveCamera(CameraUpdateFactory.newLatLng(latlng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(zoom), 2000, null);
}
It works correctly in debug via Android Studio, using a Nexus 5 with the latest Android installed. The problem is when I run a release build. The marker is added in the correct place, the zoom animation works correctly, zooming to the correct level. But it doesn't move to the marker I added.
Use this
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, zoom));
Or
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latlng, zoom), 2000, null);
Don't call both method right after each other.
you should pass the result value of CameraUpdateFactory.newLatLngZoom(latlng, zoom) to animateCamera which returns a CameraUpdate that moves the center of the screen to a latitude and longitude specified by a LatLng object, and moves to the given zoom level. You can read more about it here
Implement GoogleApiClient.ConnectionCallbacks and override onConnected method as follows:
#Override
public void onConnected(Bundle bundle) {
Toast.makeText(this, "onConnected", Toast.LENGTH_SHORT).show();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
mGMLastKnownLocation = LocationServices.FusedLocationApi.getLastLocation(mGMGoogleApiClient);
try {
// Get LocationManager object from System Service LOCATION_SERVICE
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// getting GPS status
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
// getting network status
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isGPSEnabled)
{
Criteria criteria = new Criteria();
String provider = locationManager.getBestProvider(criteria, true);
//You can still do this if you like, you might get lucky
mGMLastKnownLocation = locationManager.getLastKnownLocation(provider);
if (mGMLastKnownLocation != null) {
//place marker at current position
mMap.clear();
// Get latitude of the current location
double latitude = mGMLastKnownLocation.getLatitude();
// Get longitude of the current location
double longitude = mGMLastKnownLocation.getLongitude();
// Create a LatLng object for the current location
latLng = new LatLng(latitude, longitude);
// Show the current location in Google Map
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// Zoom in the Google Map
mMap.animateCamera(CameraUpdateFactory.zoomTo(7));
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(latitude, longitude)).title("You are here!").snippet("Consider yourself located").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
mCurrLocation = mMap.addMarker(markerOptions);
} else {
mGMLocationRequest = new LocationRequest();
mGMLocationRequest.setInterval(5000); //5 seconds
mGMLocationRequest.setFastestInterval(3000); //3 seconds
mGMLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGMGoogleApiClient, mGMLocationRequest, this);
}
} else {
//prompt user to enable location
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(i);
}
}
} catch (Exception e) {
Log.e("Error : Location", "Impossible to connect to LocationManager", e);
}
}
Also, implement LocationListener and override the onLocationChanged method as follows:
#Override
public void onLocationChanged(Location location) {
//remove previous current location marker and add new one at current position
if (mCurrLocation != null) {
mCurrLocation.remove();
}
double latitude = location.getLatitude();
double longitude = location.getLongitude();
latLng = new LatLng(latitude, longitude);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(14));
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(latitude, longitude)).title("Position").snippet("I am here").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
mCurrLocation = mMap.addMarker(markerOptions);
Toast.makeText(this, "Location Changed", Toast.LENGTH_SHORT).show();
//If you only need one location, unregister the listener
LocationServices.FusedLocationApi.removeLocationUpdates(mGMGoogleApiClient, this);
}
I hope it helps!!