Android get location is null after phone reboot - android

In my app im getting the phone's location via this function, but when I restart the phone and start the app I get null from this method. Is there something that im missing or doing wrong? What should I do to fix this issue?
Here is the function im using:
public void getAddress() {
Log.v("--", "get address 1");
boolean isGPSProviderEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean network_enabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Log.v("--", "get address 31 " + isGPSProviderEnabled + " gps - "
+ isConnectedToNetwork());
if (isGPSProviderEnabled || network_enabled) {
Log.v("--", "get address 2");
Criteria c = new Criteria();
Log.v("--", "provider " + locationManager.getBestProvider(c, true));
locationManager.requestSingleUpdate(
locationManager.getBestProvider(c, true),
mLocationListener, Looper.myLooper());
location = locationManager.getLastKnownLocation(locationManager
.getBestProvider(c, true));
if (location == null) {
Log.v("--", "get address 6");
// TODO check if this is working
locationManager.requestSingleUpdate(
locationManager.getBestProvider(c, true),
mLocationListener, Looper.myLooper());
locationManager.requestLocationUpdates(
locationManager.getBestProvider(c, true), 0, 0,
mLocationListener);
Location oldLocation = new Location("");
oldLocation.setLatitude(new Double(prefs.getString(
Constants.LATITUDE, "48.51")));
oldLocation.setLongitude(new Double(prefs.getString(
Constants.LONGITUDE, "2.20")));
populateList(oldLocation);
// locationManager.requestLocationUpdates(
// locationManager.getBestProvider(c, true), 1000, 100,
// mLocationListener);
} else {
Log.v("--", "get address 3");
if (isConnectedToNetwork()) {
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
try {
com.quanticapps.athan.utils.Geocoder geocoder = new com.quanticapps.athan.utils.Geocoder(
Main.this);
GeocoderModel geocoderModel = geocoder
.getFromLocation(
location.getLatitude(),
location.getLongitude(), 5);
city = geocoderModel.getCity();
country = geocoderModel.getCountry();
prefs.edit().putString(Constants.CITY, city)
.apply();
Log.v("--", "get address 4");
} catch (IOException e) {
Log.v("--", "get address 11");
e.printStackTrace();
} catch (LimitExceededException e) {
Log.v("--", "get address 12");
e.printStackTrace();
}
return null;
};
protected void onPostExecute(Void result) {
prefs.edit().putString(Constants.COUNTRY, country)
.apply();
prefs.edit().putString(Constants.CITY, city)
.apply();
populateList(location);
};
}.execute();
} else {
city = null;
Log.v("--", "get address 33 " + location.getLatitude());
populateList(location);
}
}
} else {
Log.v("--", "get address 5");
startGpsEnableDialog();
}
}
and my location listener:
private final LocationListener mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(final Location location) {
// TODO
Log.v("--", "get address 121");
if (location != null) {
Main.this.location = location;
getAddress();
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
Log.v("--", "provider enabled");
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
Log.v("--", "provider disabled");
}
};

When the phone is rebooted the cached last location is lost so if you didnt open up an app that uses GPS like google maps or something then there will be no last location.
There never has to be a location returned to you, you should always assume it could be null

in case that fusedLocationClient returned null location then you should get the location by yourself using requestLocationUpdates
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
if (location == null) {
checkLocationSettingsAndStartLocationUpdates(
resolutionForResult
)
} else {
showUserCurrentLocation(location)
}
}
first let's define resolutionForResult
private val resolutionForResult =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->
if (activityResult.resultCode == RESULT_OK)
locationManger.startLocationUpdates(requestPermissionLauncher)
else {
showMessage("we can't determine your location")
}
}
then this method
private fun checkLocationSettingsAndStartLocationUpdates(
resolutionForResult: ActivityResultLauncher<IntentSenderRequest>
) {
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
val client: SettingsClient = LocationServices.getSettingsClient(requireContext)
val task: Task<LocationSettingsResponse> = client.checkLocationSettings(builder.build())
task.addOnSuccessListener { _ ->
startLocationUpdates()
}
task.addOnFailureListener { exception ->
if (exception is ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
val intentSenderRequest =
IntentSenderRequest.Builder(exception.resolution).build()
resolutionForResult.launch(intentSenderRequest)
} catch (sendEx: IntentSender.SendIntentException) {
}
}
}
}
then startLocationUpdates where the actual location updates happens
fun startLocationUpdates(
) {
if (ActivityCompat.checkSelfPermission(
requireContext,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
requestPermissionLauncher.launch(
Manifest.permission.ACCESS_FINE_LOCATION
)
return
}
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
here is also the declaration of locationRequest and locationCallback
private val locationRequest: LocationRequest by lazy {
LocationRequest.create().apply {
interval = 10000
fastestInterval = 5000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
}
and
private var locationCallback: LocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations) {
if (location != null) {
//showUserCurrentLocation(location)
stopLocationUpdates(this)//if you only need the location once then stop the updates
break
}
}
}
}
here is stopLocationUpdates method
fun stopLocationUpdates(locationCallback: LocationCallback) {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
also the fusedLocationClient is defined once the user gives the permission or after the check for the permission,
Here is how to check if permission guaranted
fun locationPermissionGranted(): Boolean {
return when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
requireContext,
Manifest.permission.ACCESS_FINE_LOCATION
) -> {
fusedLocationClient =
LocationServices.getFusedLocationProviderClient(requireContext)
true
}
else -> {
false
}
}
}
in case of false then you would need to ask for the permissionfun
requestPermission(requestPermissionLauncher: ActivityResultLauncher<String>) {
requestPermissionLauncher.launch(
Manifest.permission.ACCESS_FINE_LOCATION
)
}
here is the definition for requestPermissionLauncher
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
fusedLocationClient =
LocationServices.getFusedLocationProviderClient(requireContext())
} else {
showMessage(
"the application can't show your " +
"current location on the map, because you denied the location permission"
)
}
}

Related

Show My Location on Button click in Android App

I have created a Floating Button on Maps. I would like to show the current location on Maps on Clicking that Button.
These looks on the end user as a process. But receiving the location and showing it on the map are 2 processes actually. I built a class because I needed it on my use case. But I can show you how to integrate with your case.
class LocationTracker(
val activity: FragmentActivity,
val locationTrackerListener: LocationTrackerListener
) {
private var fusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(activity)
private var locationCallback: LocationCallback? = null
private var locationRequest: LocationRequest? = null
fun startLocationRequestProcess() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
) {
activity.requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
), REQUEST_LOCATION_PERMISSION
)
} else {
getUserLocation()
}
} else {
getUserLocation()
}
}
fun getUserLocation() {
locationRequest = LocationRequest.create()?.apply {
interval = 10000
fastestInterval = 5000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
//please check the docs for other constants. this is the minimum used
}
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest!!)
val client: SettingsClient = LocationServices.getSettingsClient(activity)
val task: Task<LocationSettingsResponse> = client.checkLocationSettings(builder.build())
task.addOnSuccessListener {
updateLocation()
}
task.addOnFailureListener { exception ->
if (exception is ResolvableApiException) {
try {
exception.startResolutionForResult(
activity,
REQUEST_CHECK_LOCATION_SETTINGS
)
} catch (sendEx: IntentSender.SendIntentException) {
sendEx.printStackTrace()
}
}
}
}
fun updateLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
) {
activity.requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
), REQUEST_LOCATION_PERMISSION
)
} else {
requestLocationUpdates()
}
} else {
requestLocationUpdates()
}
}
private fun requestLocationUpdates() {
try {
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult == null) {
locationTrackerListener.onLocationError()
} else {
//you've got the response
locationTrackerListener.onLocationResult(locationResult)
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
} catch (securityException: SecurityException) {
securityException.printStackTrace()
}
}
fun removeLocationRequest() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
}
Class is set up: So onClick of your button:
fab.setOnClickListener{
//hope you have instatiated it
locationTracker.startLocationRequestProcess()
}
And later in the class you need the lat and long:
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
addMarkerToMapAndPerhapsZoom(location.latitude, location.longitude)
}
}
The interface I am using:
interface LocationTrackerListener {
fun onLocationError()
fun onLocationResult(locationResult: LocationResult)
}
Excuse duplicate code for permissions but the IDE shows errors when refactoring that and I really hate it. You can also consider to get the last known location but the problem with that is that it gives null when the user is first time visitor to the app.
first create MyLocation class like this :
import java.util.Timer;
import java.util.TimerTask;
import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class MyLocation {
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled = false;
boolean network_enabled = false;
#SuppressLint("MissingPermission")
public boolean getLocation(Context context, LocationResult result) {
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult = result;
if (lm == null)
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
}
//don't start listeners if no provider is enabled
if (!gps_enabled && !network_enabled)
return false;
if (gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if (network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1 = new Timer();
timer1.schedule(new GetLastLocation(), 20000);
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
class GetLastLocation extends TimerTask {
#SuppressLint("MissingPermission")
#Override
public void run() {
lm.removeUpdates(locationListenerGps);
lm.removeUpdates(locationListenerNetwork);
Location net_loc = null, gps_loc = null;
if (gps_enabled)
gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (network_enabled)
net_loc = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//if there are both values use the latest one
if (gps_loc != null && net_loc != null) {
if (gps_loc.getTime() > net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
}
if (gps_loc != null) {
locationResult.gotLocation(gps_loc);
return;
}
if (net_loc != null) {
locationResult.gotLocation(net_loc);
return;
}
locationResult.gotLocation(null);
}
}
public static abstract class LocationResult {
public abstract void gotLocation(Location location);
}
}
then use it in your googleMap class :
floatingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& context.checkSelfPermission(
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
context.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
} else {
MyLocation.LocationResult locationResult = new MyLocation.LocationResult() {
#Override
public void gotLocation(Location location) {
if (location != null) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(latLng, 14);
mGoogleMap.animateCamera(update);
}
}
};
MyLocation myLocation = new MyLocation();
myLocation.getLocation(this, locationResult);
}
}
});
and do not forget to add permission ACCESS_FINE_LOCATION in your AndroidManifest :
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

android location - cannot get location in service when app is background

I cannot get location in service with interval time, when app is background. Service works and gets location but location is not updating, gets old location. I test via xiaomi, maybe problem with miui? I tried about 5-10 way but result is same. Get location old when I open app location get new and close the app, get location with old latitude and longitude
for example first way:
locationManager = getApplicationContext().getSystemService(LOCATION_SERVICE) as LocationManager
isGPSEnable = locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER)
isNetworkEnable = locationManager!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
if (!isGPSEnable && !isNetworkEnable) {
} else {
Log.e(TAG,"${isGPSEnable} ")
if (isGPSEnable) {
location = null
locationManager!!.requestLocationUpdates(LocationManager.GPS_PROVIDER, LastKnownService.LOCATION_INTERVAL.toLong(), 0f, this)
if (locationManager != null) {
location = locationManager!!.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (App.lastKnownLocation == null){
if (location != null) {
MLog.d(TAG,"${location!!.latitude} ${location!!.longitude} == none")
App.lastKnownLocation = location
sendLocation(App.lastKnownLocation!!)
latitude = location!!.getLatitude()
longitude = location!!.getLongitude()
fn_update(location!!)
}
}else{
if (location != null) {
MLog.d(TAG,"${location!!.latitude} ${location!!.longitude} == ${location!!.distanceTo(App.lastKnownLocation)}")
App.lastKnownLocation = location
latitude = location!!.getLatitude()
longitude = location!!.getLongitude()
fn_update(location!!)
sendLocation(App.lastKnownLocation!!)
}
}
}
}else if (isNetworkEnable) {
location = null
locationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LastKnownService.LOCATION_INTERVAL.toLong(), 0f, this)
if (locationManager != null) {
location = locationManager!!.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
if (App.lastKnownLocation == null){
if (location != null) {
MLog.d(TAG,"${location!!.latitude} ${location!!.longitude} == none")
App.lastKnownLocation = location
sendLocation(App.lastKnownLocation!!)
latitude = location!!.getLatitude()
longitude = location!!.getLongitude()
fn_update(location!!)
}
}else{
if (location != null) {
MLog.d(TAG,"${location!!.latitude} ${location!!.longitude} == ${location!!.distanceTo(App.lastKnownLocation)}")
App.lastKnownLocation = location
latitude = location!!.getLatitude()
longitude = location!!.getLongitude()
fn_update(location!!)
sendLocation(App.lastKnownLocation!!)
}
}
}
}
}
second way:
mLocationManager!!.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL.toLong(), LOCATION_DISTANCE,
mLocationListeners[1])
private var mLocationListeners = arrayOf(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))
private inner class LocationListener(provider: String) : android.location.LocationListener {
internal var mLastLocation: Location
init {
Log.e(TAG, "LocationListener $provider")
mLastLocation = Location(provider)
}
override fun onLocationChanged(location: Location) {
Log.e(TAG, "onLocationChanged: $location")
try{
val mBuilder = NotificationCompat.Builder(this#LocationService, "123")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("location sended")
.setContentText("onlocation changed")
.setStyle(NotificationCompat.BigTextStyle()
.bigText("onlocation changed"))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
if (notificationManager != null) notificationManager!!.notify(1,mBuilder.build())
val distance = location.distanceTo(mLastLocation)
if (distance > 10){
mLastLocation = location
sendLocation(mLastLocation)
}
}catch (e :java.lang.Exception){
Log.e(TAG, "send http lat lon exception: $e")
}
mLastLocation.set(location)
}
override fun onProviderDisabled(provider: String) {
Log.e(TAG, "onProviderDisabled: $provider")
}
override fun onProviderEnabled(provider: String) {
Log.e(TAG, "onProviderEnabled: $provider")
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
Log.e(TAG, "onStatusChanged: $provider")
}
}
You have to remove battery optimize restriction for your app in Battery optimization manually( go to battery option from Security app and select no restriction for your app), then it will work.. But how to do it programmatically , i am also searching for that..thanks
call this method:
private fun openMiuiPowerKeeper(context: Context) {
context.startActivity(Intent().apply {
setClassName(
"com.miui.powerkeeper",
"com.miui.powerkeeper.ui.HiddenAppsConfigActivity"
)
putExtra("package_name", context.packageName)
putExtra("package_label", context.getString(R.string.app_name))
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}
it open window, where user need line "not restriction". And you need check is miui firmware on device or something else, for instance, like this:
private fun isFirmwareMiui(context: Context): Boolean {
if (Build.MANUFACTURER.equals("xiaomi", true)) {
context.packageManager.getInstalledPackages(PackageManager.GET_META_DATA).forEach {
return it.packageName.startsWith("com.miui.")
}
}
return false
}

Trouble finding current Location Android [duplicate]

How do I get the current Latitude and Longitude of the mobile device in android using location tools?
Use the LocationManager.
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
double longitude = location.getLongitude();
double latitude = location.getLatitude();
The call to getLastKnownLocation() doesn't block - which means it will return null if no position is currently available - so you probably want to have a look at passing a LocationListener to the requestLocationUpdates() method instead, which will give you asynchronous updates of your location.
private final LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
longitude = location.getLongitude();
latitude = location.getLatitude();
}
}
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, locationListener);
You'll need to give your application the ACCESS_FINE_LOCATION permission if you want to use GPS.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
You may also want to add the ACCESS_COARSE_LOCATION permission for when GPS isn't available and select your location provider with the getBestProvider() method.
Here is the class LocationFinder to find the GPS location. This class will call MyLocation, which will do the business.
LocationFinder
public class LocationFinder extends Activity {
int increment = 4;
MyLocation myLocation = new MyLocation();
// private ProgressDialog dialog;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intermediat);
myLocation.getLocation(getApplicationContext(), locationResult);
boolean r = myLocation.getLocation(getApplicationContext(),
locationResult);
startActivity(new Intent(LocationFinder.this,
// Nearbyhotelfinder.class));
GPSMyListView.class));
finish();
}
public LocationResult locationResult = new LocationResult() {
#Override
public void gotLocation(Location location) {
// TODO Auto-generated method stub
double Longitude = location.getLongitude();
double Latitude = location.getLatitude();
Toast.makeText(getApplicationContext(), "Got Location",
Toast.LENGTH_LONG).show();
try {
SharedPreferences locationpref = getApplication()
.getSharedPreferences("location", MODE_WORLD_READABLE);
SharedPreferences.Editor prefsEditor = locationpref.edit();
prefsEditor.putString("Longitude", Longitude + "");
prefsEditor.putString("Latitude", Latitude + "");
prefsEditor.commit();
System.out.println("SHARE PREFERENCE ME PUT KAR DIYA.");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
// handler for the background updating
}
MyLocation
public class MyLocation {
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled=false;
boolean network_enabled=false;
public boolean getLocation(Context context, LocationResult result)
{
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult=result;
if(lm==null)
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}
//Toast.makeText(context, gps_enabled+" "+network_enabled, Toast.LENGTH_LONG).show();
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled)
return false;
if(gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1=new Timer();
timer1.schedule(new GetLastLocation(), 10000);
// Toast.makeText(context, " Yaha Tak AAya", Toast.LENGTH_LONG).show();
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
class GetLastLocation extends TimerTask {
#Override
public void run() {
//Context context = getClass().getgetApplicationContext();
Location net_loc=null, gps_loc=null;
if(gps_enabled)
gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(network_enabled)
net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//if there are both values use the latest one
if(gps_loc!=null && net_loc!=null){
if(gps_loc.getTime()>net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
}
if(gps_loc!=null){
locationResult.gotLocation(gps_loc);
return;
}
if(net_loc!=null){
locationResult.gotLocation(net_loc);
return;
}
locationResult.gotLocation(null);
}
}
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
}
With google things changes very often: non of the previous answers worked for me.
based on this google training here is how you do it using
fused location provider
this requires Set Up Google Play Services
Activity class
public class GPSTrackerActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
Location mLastLocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
protected void onStart() {
mGoogleApiClient.connect();
super.onStart();
}
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(Bundle bundle) {
try {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
Intent intent = new Intent();
intent.putExtra("Longitude", mLastLocation.getLongitude());
intent.putExtra("Latitude", mLastLocation.getLatitude());
setResult(1,intent);
finish();
}
} catch (SecurityException e) {
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
usage
in you activity
Intent intent = new Intent(context, GPSTrackerActivity.class);
startActivityForResult(intent,1);
And this method
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1){
Bundle extras = data.getExtras();
Double longitude = extras.getDouble("Longitude");
Double latitude = extras.getDouble("Latitude");
}
}
you can got Current latlng using this
`
public class MainActivity extends ActionBarActivity {
private LocationManager locationManager;
private String provider;
private MyLocationListener mylistener;
private Criteria criteria;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Define the criteria how to select the location provider
criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE); //default
// user defines the criteria
criteria.setCostAllowed(false);
// get the best provider depending on the criteria
provider = locationManager.getBestProvider(criteria, false);
// the last known location of this provider
Location location = locationManager.getLastKnownLocation(provider);
mylistener = new MyLocationListener();
if (location != null) {
mylistener.onLocationChanged(location);
} else {
// leads to the settings because there is no last known location
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
// location updates: at least 1 meter and 200millsecs change
locationManager.requestLocationUpdates(provider, 200, 1, mylistener);
String a=""+location.getLatitude();
Toast.makeText(getApplicationContext(), a, 222).show();
}
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
// Initialize the location fields
Toast.makeText(MainActivity.this, ""+location.getLatitude()+location.getLongitude(),
Toast.LENGTH_SHORT).show()
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Toast.makeText(MainActivity.this, provider + "'s status changed to "+status +"!",
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(MainActivity.this, "Provider " + provider + " enabled!",
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider) {
Toast.makeText(MainActivity.this, "Provider " + provider + " disabled!",
Toast.LENGTH_SHORT).show();
}
}
`
Above solutions is also correct, but some time if location is null then it crash the app or not working properly. The best way to get Latitude and Longitude of android is:
Geocoder geocoder;
String bestProvider;
List<Address> user = null;
double lat;
double lng;
LocationManager lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
bestProvider = lm.getBestProvider(criteria, false);
Location location = lm.getLastKnownLocation(bestProvider);
if (location == null){
Toast.makeText(activity,"Location Not found",Toast.LENGTH_LONG).show();
}else{
geocoder = new Geocoder(activity);
try {
user = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
lat=(double)user.get(0).getLatitude();
lng=(double)user.get(0).getLongitude();
System.out.println(" DDD lat: " +lat+", longitude: "+lng);
}catch (Exception e) {
e.printStackTrace();
}
}
Best way is
Add permission manifest file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Then you can get GPS location or if GPS location is not available then this function return NETWORK location
public static Location getLocationWithCheckNetworkAndGPS(Context mContext) {
LocationManager lm = (LocationManager)
mContext.getSystemService(Context.LOCATION_SERVICE);
assert lm != null;
isGpsEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkLocationEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Location networkLoacation = null, gpsLocation = null, finalLoc = null;
if (isGpsEnabled)
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}gpsLocation = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (isNetworkLocationEnabled)
networkLoacation = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (gpsLocation != null && networkLoacation != null) {
//smaller the number more accurate result will
if (gpsLocation.getAccuracy() > networkLoacation.getAccuracy())
return finalLoc = networkLoacation;
else
return finalLoc = gpsLocation;
} else {
if (gpsLocation != null) {
return finalLoc = gpsLocation;
} else if (networkLoacation != null) {
return finalLoc = networkLoacation;
}
}
return finalLoc;
}
You can use FusedLocationProvider
For using Fused Location Provider in your project you will have to add the google play services location dependency in our app level build.gradle file
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
...
...
implementation 'com.google.android.gms:play-services-location:17.0.0'
}
Permissions in Manifest
Apps that use location services must request location permissions. Android offers two location permissions: ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
As you may know that from Android 6.0 (Marshmallow) you must request permissions for important access in the runtime. Cause it’s a security issue where while installing an application, user may not clearly understand about an important permission of their device.
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_ID
)
Then you can use the FusedLocationProvider Client to get the updated location in your desired place.
mFusedLocationClient.lastLocation.addOnCompleteListener(this) { task ->
var location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
findViewById<TextView>(R.id.latTextView).text = location.latitude.toString()
findViewById<TextView>(R.id.lonTextView).text = location.longitude.toString()
}
}
You can also check certain configuration like if the device has location settings on or not. You can also check the article on Detect Current Latitude & Longitude using Kotlin in Android for more functionality.
If there is no cache location then it will catch the current location using:
private fun requestNewLocationData() {
var mLocationRequest = LocationRequest()
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest.interval = 0
mLocationRequest.fastestInterval = 0
mLocationRequest.numUpdates = 1
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
mFusedLocationClient!!.requestLocationUpdates(
mLocationRequest, mLocationCallback,
Looper.myLooper()
)
}
Plug and play location-manager that can be used both in XML-based projects and Jetpack Compose projects (personally using it in JetpackCompose)
class LocationManager(context: Context): LocationCallback() {
val context = context
var publicCompletion: ((Double, Double) -> Unit)? = null
var fusedLocationProviderClient = FusedLocationProviderClient(
context
)
fun requestLocationPermission() {
val activity = context as Activity?
ActivityCompat.requestPermissions(
activity!!,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION
),
101
)
}
fun checkIfLocationPermissionIsGranted(): Boolean {
return (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
)
}
fun getLatitudeLongitude(completion: (Double, Double) -> Unit) {
publicCompletion = { latitude, longitude ->
completion(latitude, longitude)
}
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
val activity = context as Activity?
fusedLocationProviderClient.lastLocation.addOnCompleteListener(activity!!) { task ->
var location: Location? = task.result
if (location != null) {
publicCompletion?.let { it(location!!.latitude, location!!.longitude) }
} else {
requestLocationUpdates()
}
}
}
}
fun requestLocationUpdates() {
var request = LocationRequest()
request.priority = com.google.android.gms.location.LocationRequest.PRIORITY_HIGH_ACCURACY
request.fastestInterval = 0
request.numUpdates = 1
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationProviderClient.requestLocationUpdates(
request, this, Looper.myLooper()
)
}
}
override fun onLocationResult(p0: LocationResult?) {
super.onLocationResult(p0)
publicCompletion?.let { it(p0!!.lastLocation!!.latitude, p0!!.lastLocation!!.longitude) }
}
override fun onLocationAvailability(p0: LocationAvailability?) {
super.onLocationAvailability(p0)
}
}
Just follow Google recommendation and prepared codes in kotlin: (Supports also Android 11 and 12):
https://github.com/googlecodelabs/while-in-use-location
and its step by step explanation:
https://codelabs.developers.google.com/codelabs/while-in-use-location

get the current location fast and once in android

I have an android application that need device current location (latitude and longitude). I've tried some tutorial on the net and specially some solutions from stack overflow, but they doesn't work well for me. My requirement is so simple: First I need it to be fast and need the location once when I the fragment starts. Second I need it to be as precise as possible, I mean it should use GPS first if GPS is not available then use Network provider.
For example, I've tried this solution but it return null after 30 second, but I know there is some all the things is ok because google map and other application works well !!!
Something that almost all the answers suggest is to use getLastKnownLocation(), but I suppose it's not the current and I don't want it if it is so.
can anyone suggest me some kind of simple and fast way to get the location just ONCE ?!
Here, you can use this...
Example usage:
public void foo(Context context) {
// when you need location
// if inside activity context = this;
SingleShotLocationProvider.requestSingleUpdate(context,
new SingleShotLocationProvider.LocationCallback() {
#Override public void onNewLocationAvailable(GPSCoordinates location) {
Log.d("Location", "my location is " + location.toString());
}
});
}
You might want to verify the lat/long are actual values and not 0 or something. If I remember correctly this shouldn't throw an NPE but you might want to verify that.
public class SingleShotLocationProvider {
public static interface LocationCallback {
public void onNewLocationAvailable(GPSCoordinates location);
}
// calls back to calling thread, note this is for low grain: if you want higher precision, swap the
// contents of the else and if. Also be sure to check gps permission/settings are allowed.
// call usually takes <10ms
public static void requestSingleUpdate(final Context context, final LocationCallback callback) {
final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isNetworkEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
}, null);
} else {
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
}, null);
}
}
}
// consider returning Location instead of this dummy wrapper class
public static class GPSCoordinates {
public float longitude = -1;
public float latitude = -1;
public GPSCoordinates(float theLatitude, float theLongitude) {
longitude = theLongitude;
latitude = theLatitude;
}
public GPSCoordinates(double theLatitude, double theLongitude) {
longitude = (float) theLongitude;
latitude = (float) theLatitude;
}
}
}
For anyone interested in retrieving a single location update, in the best, idiomatic way, using the latest APIs, and the magic of Kotlin, here you go:
Gradle dependency:
dependencies {
...
implementation "com.google.android.gms:play-services-location:18.0.0"
...
}
Manifest permissions:
<manifest>
...
<!-- required only for LocationRequest.PRIORITY_HIGH_ACCURACY -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- required for all other priorities -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
...
</manifest>
Somewhere in your Extensions file:
// To use PRIORITY_HIGH_ACCURACY, you must have ACCESS_FINE_LOCATION permission.
// Any other priority will require just ACCESS_COARSE_LOCATION,
// but will not guarantee a location update
#SuppressLint("MissingPermission")
suspend fun FusedLocationProviderClient.awaitCurrentLocation(priority: Int): Location? {
return suspendCancellableCoroutine {
// to use for request cancellation upon coroutine cancellation
val cts = CancellationTokenSource()
getCurrentLocation(priority, cts.token)
.addOnSuccessListener {location ->
// remember location is nullable, this happens sometimes
// when the request expires before an update is acquired
it.resume(location)
}.addOnFailureListener {e ->
it.resumeWithException(e)
}
it.invokeOnCancellation {
cts.cancel()
}
}
}
In your fragment:
// need to register this anywhere before onCreateView, idealy as a field
private val permissionRequester = registerForActivityResult(
// you can use RequestPermission() contract if you only need 1 permission
ActivityResultContracts.RequestMultiplePermissions()
) { map ->
// If you requested 1 permission, change `map` to `isGranted`
// Keys are permissions Strings, values are isGranted Booleans
// An easy way to check if "any" permission was granted is map.containsValue(true)
// You can use your own logic for multiple permissions,
// but they have to follow the same checks here:
val response = map.entries.first()
val permission = response.key
val isGranted = response.value
when {
isGranted -> onPermissionGranted()
ActivityCompat.shouldShowRequestPermissionRationale(requireContext(), permission) -> {
// permission denied but not permanently, tell user why you need it.
// Idealy provide a button to request it again and another to dismiss
AlertDialog.Builder(requireContext())
.setTitle(R.string.perm_request_rationale_title)
.setMessage(R.string.perm_request_rationale)
.setPositiveButton(R.string.request_perm_again) { _, _ ->
requirePermission()
}
.setNegativeButton(R.string.dismiss, null)
.create()
.show()
}
else -> {
// permission permanently denied
// 1) tell user the app won't work as expected, or
// 2) take him to your app's info screen to manually change permissions, or
// 3) silently and gracefully degrade user experience
// I'll leave the implementation to you
}
}
}
onPermissionGranted function:
private fun onPermissionGranted() {
val lm = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
if(LocationManagerCompat.isLocationEnabled(lm)) {
// you can do this your own way, eg. from a viewModel
// but here is where you wanna start the coroutine.
// Choose your priority based on the permission you required
val priority = LocationRequest.PRIORITY_HIGH_ACCURACY
lifecycleScope.launch {
val location = LocationServices
.getFusedLocationProviderClient(requireContext())
.awaitCurrentLocation(priority)
// do whatever with this location, notice that it's nullable
}
} else {
// prompt user to enable location or launch location settings check
}
}
Now all you have to do is add this to MyLocation button click listener:
private fun requirePermission() {
val permissions = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
// optional: Manifest.permission.ACCESS_COARSE_LOCATION
)
permissionRequester.launch(permissions)
}
Note that this has the beauty of checking if the permission was already given implicitly, and not show a dialog/request if that was the case.
Ergo, always start your flow by launching the requester and only do your checks in its callback.
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
Requesting User Permissions
build.gradle (Module: app)
dependencies {
...
implementation 'com.google.android.gms:play-services-location:15.0.0'
...
}
If you receive an error, check that your top-level build.gradle
contains a reference to the google() repo or to maven { url
"https://maven.google.com" }
Set Up Google Play Services
LocationService.kt
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.net.Uri
import android.os.Looper
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.*
import org.jetbrains.anko.alert
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.okButton
object LocationService {
#SuppressLint("StaticFieldLeak")
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
doAsync {
location = locationResult.lastLocation
onSuccess(location)
}
}
}
private lateinit var onSuccess: (location : Location) -> Unit
private lateinit var onError: () -> Unit
lateinit var location: Location
fun init(activity: Activity) {
fusedLocationProviderClient = FusedLocationProviderClient(activity)
locationRequest = LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(1000).setFastestInterval(1000).setNumUpdates(1)
}
private fun checkLocationStatusAndGetLocation(activity: Activity) {
doAsync {
when {
ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED -> LocationServices.getSettingsClient(activity).checkLocationSettings(LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true).build()).addOnCompleteListener { task ->
doAsync {
try {
task.getResult(ApiException::class.java)
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
} catch (exception: ApiException) {
when (exception.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
try {
(exception as ResolvableApiException).startResolutionForResult(activity, 7025)
} catch (ex: Exception) {
promptShowLocation(activity)
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
promptShowLocation(activity)
}
}
}
}
}
ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION) -> activity.runOnUiThread {
activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") {
okButton {
val ite = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", activity.packageName, null))
ite.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.startActivity(ite)
onError()
}
negativeButton("Cancelar", { onError() })
onCancelled { onError() }
}.show()
}
else -> ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 7024)
}
}
}
private fun promptShowLocation(activity: Activity) {
activity.runOnUiThread {
activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") {
okButton {
activity.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
onError()
}
negativeButton("Cancelar", { onError() })
onCancelled { onError() }
}.show()
}
}
fun onRequestPermissionsResult(activity: Activity, requestCode: Int, grantResults: IntArray) {
if (requestCode == 7024) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkLocationStatusAndGetLocation(activity)
} else {
onError()
}
}
}
fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int) {
if (requestCode == 7025) {
if (resultCode == Activity.RESULT_OK) {
checkLocationStatusAndGetLocation(activity)
} else {
onError()
}
}
}
fun getLocation(activity: Activity, onSuccess: () -> Unit, onError: () -> Unit) {
this.onSuccess = onSuccess
this.onError = onError
checkLocationStatusAndGetLocation(activity)
}
}
your activity
override fun onCreate(savedInstanceState: Bundle?) {
...
LocationService.init(this)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
LocationService.onRequestPermissionsResult(this, requestCode, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
LocationService.onActivityResult(this, requestCode, resultCode)
}
private fun yourFunction() {
LocationService.getLocation(this, { location ->
//TODO: use the location
}, {
//TODO: display error message
})
}
AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
MainActivity.java:
public class MainActivity extends AppCompatActivity implements LocationListener {
private LocationManager locationManager;
private Location onlyOneLocation;
private final int REQUEST_FINE_LOCATION = 1234;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
}
#Override public void onLocationChanged(Location location) {
onlyOneLocation = location;
locationManager.removeUpdates(this);
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("gps", "Location permission granted");
try {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates("gps", 0, 0, this);
}
catch (SecurityException ex) {
Log.d("gps", "Location permission did not work!");
}
}
break;
}
}
What you want to do is achieved using the LocationManager#requestSingleUpdate. This method attaches a listener in a given looper (if you want or have it) and notifies the location ASAP it is received, only once. The method you suggest is used only as an inexact position before the real one is given to you.
In any case it will be fast than milliseconds (unless you are lucky enough to start listening when a location came to the device). Think on the GPS as an element that you enable when waiting for locations and disable when you remove this listening. This behavior is done to avoid draining the user's battery.
So, to sum up:
The time between you start listening and you receive the position depends on the device's GPS (manufacture, location of the user, satellite coverage...)
There is a method in the Android SDK to listen for a single update.
By providing the a criteria object, you can manage which criterias are acceptable for you to receive a location. Stronger criterias means more time to get an accurate response.
// Get LocationManager object
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Create a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Get the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Get Current Location
Location myLocation = locationManager.getLastKnownLocation(provider);
//latitude of location
double myLatitude = myLocation.getLatitude();
//longitude og location
double myLongitude = myLocation.getLongitude();
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;
}
All the above answers are not worked for me so I answered this
Initially add the dependencies
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
after add the class MyLocationListiner.java
package com.example.firebase_auth;
/**
* Created by Chromicle(Ajay Prabhakar).
*/
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import static android.content.Context.LOCATION_SERVICE;
public class MyLocationListener implements LocationListener {
public static double latitude;
Context ctx;
Location location;
LocationManager locationManager;
boolean isGPSEnabled = false;
boolean isNetworkEnabled = false;
public static double longitude;
MyLocationListener(Context ctx) {
this.ctx = ctx;
try {
locationManager = (LocationManager) ctx.getSystemService(LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
Toast.makeText(ctx, "GPS Enable " + isGPSEnabled, Toast.LENGTH_LONG).show();
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Toast.makeText(ctx, "Network Enable " + isNetworkEnabled, Toast.LENGTH_LONG).show();
if ( Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission
( ctx, android.Manifest.permission.ACCESS_FINE_LOCATION )
!= PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission( ctx,
android.Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) { }
if (isGPSEnabled == true) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
if (isNetworkEnabled==true) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, this);
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(ctx,"latitude: "+latitude+" longitude: "+longitude,Toast.LENGTH_LONG).show();
}
catch(Exception ex)
{
Toast.makeText(ctx,"Exception "+ex, Toast.LENGTH_LONG).show();
}
}
#Nullable
#Override
public void onLocationChanged(Location loc)
{
loc.getLatitude();
loc.getLongitude();
latitude=loc.getLatitude();
longitude=loc.getLongitude();
}
#Override
public void onProviderDisabled(String provider)
{
//print "Currently GPS is Disabled";
}
#Override
public void onProviderEnabled(String provider)
{
//print "GPS got Enabled";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
To use that class add this method
location is stored in the Address string
public void getLocation(){
Double latitude = 0.0, longitude;
String message = "";
LocationManager mlocManager = null;
LocationListener mlocListener;
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener(this);
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;
}
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
latitude = MyLocationListener.latitude;
longitude = MyLocationListener.longitude;
message = message +"https://www.google.com/maps/dir/#"+ latitude +","+ longitude;
address=message;
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
if (latitude == 0.0) {
Toast.makeText(getApplicationContext(), "Currently gps has not found your location....", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(getApplicationContext(), "GPS is currently off...", Toast.LENGTH_LONG).show();
}
}
Hope it helpfull
I have created some classes using those you can easily get the current location. I used FusedLocationProviderClient for getting the current location.
First Add this into your manifest File:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Then Check for location permission:
private fun startCheckingLocation() {
if (checkLocationPermissions() == true) {
checkGPSEnabled()
} else {
askLocationPermission()
}
}
checkLocationPermissions method:
private fun checkLocationPermissions(): Boolean? {
return PermissionUtils.hasPermissions(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
}
checkGPSEnabled method:
private fun checkGPSEnabled() {
GpsUtils(requireContext()) {
it?.let {
startCheckingCurrentLocation()
}
}.apply {
turnGPSOn(gpsDialogCallback)
}
}
As OnActivityResult is Deprecated:
private val gpsDialogCallback = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->
activityResult?.let { result ->
when (result.resultCode) {
RESULT_OK -> {
startCheckingCurrentLocation()
}
RESULT_CANCELED -> {
}
}
}
}
startCheckingCurrentLocation method :
private fun startCheckingCurrentLocation() {
LocationUtils(requireContext()) { location ->
Log.d(TAG, ">>>>>>>>>>>>>>" + location.latitude + " " + location.longitude)
startIntentService(location)
}.apply {
startLocationUpdates()
}
}
For GPS I have created one class that you can simply put and use it:
GPSUtils:
class GpsUtils(
private val context: Context,
private val gpsStatus: (isEnable: Boolean?) -> Unit
) {
private val mSettingsClient: SettingsClient = LocationServices.getSettingsClient(context)
private val mLocationSettingsRequest: LocationSettingsRequest
private val locationManager: LocationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
private val locationRequest: LocationRequest = LocationRequest.create()
init {
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.interval = 10 * 1000.toLong()
locationRequest.fastestInterval = 2 * 1000.toLong()
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
mLocationSettingsRequest = builder.build()
builder.setAlwaysShow(true) //this is the key ingredient
}
// method for turn on GPS
fun turnGPSOn(gpsDialogCallback: ActivityResultLauncher<IntentSenderRequest>) {
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
gpsStatus.invoke(true)
} else {
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(
(context as Activity)
) {
// GPS is already enable, callback GPS status through listener
gpsStatus.invoke(true)
}
.addOnFailureListener(context) { e ->
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
// Show the dialog by calling startResolutionForResult() and check the result in onActivityResult().
if (e is ResolvableApiException) {
try {
val intentSenderRequest = IntentSenderRequest.Builder(e.resolution).build()
gpsDialogCallback.launch(intentSenderRequest)
} catch (throwable: Throwable) {
// Ignore the error.
}
}
} catch (sie: IntentSender.SendIntentException) {
// Ignore the error.
Timber.i("PendingIntent unable to execute request.")
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
val errorMessage =
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
Timber.e(errorMessage)
}
LocationSettingsStatusCodes.CANCELED -> {
val errorMessage =
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
Timber.e(errorMessage)
}
LocationSettingsStatusCodes.SUCCESS -> {
// All location settings are satisfied. The client can initialize location
// requests here.
val errorMessage =
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
Timber.e(errorMessage)
}
}
}
}
}
}
For checking location I have created one more class :
class LocationUtils(
context: Context,
private val latLng: (location: Location) -> Unit) {
private var fusedLocationClient: FusedLocationProviderClient? = null
private val locationRequest = LocationRequest.create()?.apply {
interval = 20 * 1000.toLong()
fastestInterval = 2 * 1000.toLong()
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
init {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
}
/**
* call when location permission is allowed and you want to fetch the last location of the user
*/
fun getLastLocation() {
fusedLocationClient?.lastLocation?.addOnSuccessListener { location ->
location?.let {
latLng.invoke(location)
stopLocationUpdates()
}
}
}
/**
* Requested location callback
*/
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations) {
location?.let {
latLng.invoke(it)
stopLocationUpdates()
}
}
super.onLocationResult(locationResult)
}
}
/**
* call when location permission is already given to user and you want to receive continues location updates
*/
fun startLocationUpdates() {
fusedLocationClient?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
/**
* call when you want to stop location updates
*/
fun stopLocationUpdates() {
fusedLocationClient?.removeLocationUpdates(locationCallback)?.addOnCompleteListener { }
}
}
I have created one worker class to get the address from latlng:
class FetchAddressWorker(
context: Context,
workerParameters: WorkerParameters
) :
Worker(context, workerParameters) {
companion object {
const val TAG = "FetchAddressWorker"
}
override fun doWork(): Result {
val geoCoder = Geocoder(applicationContext, Locale.getDefault())
var errorMessage = ""
val lat: Double = inputData.getDouble(CPKConstants.LATITUDE, 0.0)
val lng: Double = inputData.getDouble(CPKConstants.LONGITUDE, 0.0)
var addresses: List<Address> = emptyList()
try {
addresses =
geoCoder.getFromLocation(lat, lng, 1)
} catch (ioException: IOException) {
// Catch network or other I/O problems.
errorMessage = "Service not available"
LogUtils.e(TAG, errorMessage, ioException)
} catch (illegalArgumentException: IllegalArgumentException) {
// Catch invalid latitude or longitude values.
errorMessage = "Invalid lat lng used"
LogUtils.e(
TAG,
"$errorMessage. Latitude = $lat , Longitude = $lng",
illegalArgumentException
)
}
// Handle case where no address was found.
if (addresses.isEmpty()) {
if (errorMessage.isEmpty()) {
errorMessage = "No Address Found"
LogUtils.e(TAG, errorMessage)
}
val data = Data.Builder()
.putString(
CPKConstants.FAILURE_RESULT,
errorMessage
)
.build()
return Result.failure(data)
} else {
val address: Address = addresses[0]
// Fetch the address lines using getAddressLine,
// join them, and send them to the thread.
val addressFragments = with(address) {
(0..maxAddressLineIndex).map { getAddressLine(it) }
}
LogUtils.i(TAG, "Address Found " + addressFragments.joinToString(separator = "\n"))
val data = Data.Builder()
.putString(
CPKConstants.SUCCESS_RESULT,
addressFragments.joinToString(separator = "\n")
)
.build()
// Indicate whether the work finished successfully with the Result
return Result.success(data)
}
}
}
Than use AddressResultReceiver in your fragment or activity:
internal inner class AddressResultReceiver(handler: Handler) : ResultReceiver(handler) {
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
// Display the address string
// or an error message sent from the intent service.
val addressOutput = resultData?.getString(AppConstants.RESULT_DATA_KEY).orEmpty()
//displayAddressOutput()
// Show a toast message if an address was found.
if (resultCode == AppConstants.SUCCESS_RESULT) {
Boast.showText(requireContext(), "Address found = $addressOutput")
txtContinueWith.text = addressOutput
}
}
}
You will need to initialize this in fragment or activity where you will use the above receiver to get the address:
private var resultReceiver = AddressResultReceiver(Handler())
These are some constants that you should use as it is.
//Location Constants
const val LOCATION_SERVICE = "LOCATION_SERVICE"
const val SUCCESS_RESULT = 0
const val FAILURE_RESULT = 1
const val PACKAGE_NAME = "com.google.android.gms.location.sample.locationaddress"
const val RECEIVER = "$PACKAGE_NAME.RECEIVER"
const val RESULT_DATA_KEY = "${PACKAGE_NAME}.RESULT_DATA_KEY"
const val LOCATION_DATA_EXTRA = "${PACKAGE_NAME}.LOCATION_DATA_EXTRA"
Start worker from view
private fun startAddressWorkManager(location: Location) {
val inputData = Data.Builder()
.putDouble(CPKConstants.LATITUDE, location.latitude)
.putDouble(CPKConstants.LONGITUDE, location.longitude)
.build()
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val fetchAddressWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<FetchAddressWorker>()
.setConstraints(constraints)
.setInputData(inputData)
.build()
WorkManager
.getInstance(this)
.enqueue(fetchAddressWorkRequest)
WorkManager.getInstance(this).getWorkInfoByIdLiveData(fetchAddressWorkRequest.id)
.observe(this,
{ workInfo ->
when (workInfo.state) {
WorkInfo.State.SUCCEEDED -> {
if (workInfo.state.isFinished) {
val addressData =
workInfo.outputData.getString(CPKConstants.SUCCESS_RESULT)
Timber.d("AddressData %s", addressData)
_binding?.searchEdt?.setText(addressData)
}
}
else -> {
Timber.d("workInfo %s", workInfo)
}
}
})
}

How do I get the current GPS location programmatically in Android?

I need to get my current location using GPS programmatically.
How can i achieve it?
I have created a small application with step by step description to get current location's GPS coordinates.
Complete example source code is in Get Current Location coordinates , City name - in Android.
See how it works:
All we need to do is add this permission in the manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
And create a LocationManager instance like this:
LocationManager locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
Check if GPS is enabled or not.
And then implement LocationListener and get coordinates:
LocationListener locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
Here is the sample code to do so
/*---------- Listener class to get coordinates ------------- */
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
editLocation.setText("");
pb.setVisibility(View.INVISIBLE);
Toast.makeText(
getBaseContext(),
"Location changed: Lat: " + loc.getLatitude() + " Lng: "
+ loc.getLongitude(), Toast.LENGTH_SHORT).show();
String longitude = "Longitude: " + loc.getLongitude();
Log.v(TAG, longitude);
String latitude = "Latitude: " + loc.getLatitude();
Log.v(TAG, latitude);
/*------- To get city name from coordinates -------- */
String cityName = null;
Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
if (addresses.size() > 0) {
System.out.println(addresses.get(0).getLocality());
cityName = addresses.get(0).getLocality();
}
}
catch (IOException e) {
e.printStackTrace();
}
String s = longitude + "\n" + latitude + "\n\nMy Current City is: "
+ cityName;
editLocation.setText(s);
}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
There are already many answers there but I want to show latest way to get location using Google API, so new programmers can use new method:
I have written detailed tutorial on current location in android at my blog demonuts.com You can also find full source code developed with android studio.
First of all, put this in gradle file
compile 'com.google.android.gms:play-services:9.0.2'
then implement necessary interfaces
public class MainActivity extends BaseActivitiy implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener
declare instances
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager locationManager;
private LocationRequest mLocationRequest;
put this in onCreate()
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
At last, override necessary methods
#Override
public void onConnected(Bundle bundle) {
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;
} startLocationUpdates();
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation == null){
startLocationUpdates();
}
if (mLocation != null) {
double latitude = mLocation.getLatitude();
double longitude = mLocation.getLongitude();
} else {
// Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
protected void startLocationUpdates() {
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
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;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
Log.d("reque", "--->>>>");
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onLocationChanged(Location location) {
}
Don't forget to start GPS in your device before running app.
Since I didn't like some of the code in the other answers, here's my simple solution. This solution is meant to be usable in an Activity or Service to track the location. It makes sure that it never returns data that's too stale unless you explicitly request stale data. It can be run in either a callback mode to get updates as we receive them, or in poll mode to poll for the most recent info.
Generic LocationTracker interface. Allows us to have multiple types of location trackers and plug the appropriate one in easily:
package com.gabesechan.android.reusable.location;
import android.location.Location;
public interface LocationTracker {
public interface LocationUpdateListener{
public void onUpdate(Location oldLoc, long oldTime, Location newLoc, long newTime);
}
public void start();
public void start(LocationUpdateListener update);
public void stop();
public boolean hasLocation();
public boolean hasPossiblyStaleLocation();
public Location getLocation();
public Location getPossiblyStaleLocation();
}
ProviderLocationTracker- this class will track the location for either GPS or NETWORK.
package com.gabesechan.android.reusable.location;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class ProviderLocationTracker implements LocationListener, LocationTracker {
// The minimum distance to change Updates in meters
private static final long MIN_UPDATE_DISTANCE = 10;
// The minimum time between updates in milliseconds
private static final long MIN_UPDATE_TIME = 1000 * 60;
private LocationManager lm;
public enum ProviderType{
NETWORK,
GPS
};
private String provider;
private Location lastLocation;
private long lastTime;
private boolean isRunning;
private LocationUpdateListener listener;
public ProviderLocationTracker(Context context, ProviderType type) {
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
if(type == ProviderType.NETWORK){
provider = LocationManager.NETWORK_PROVIDER;
}
else{
provider = LocationManager.GPS_PROVIDER;
}
}
public void start(){
if(isRunning){
//Already running, do nothing
return;
}
//The provider is on, so start getting updates. Update current location
isRunning = true;
lm.requestLocationUpdates(provider, MIN_UPDATE_TIME, MIN_UPDATE_DISTANCE, this);
lastLocation = null;
lastTime = 0;
return;
}
public void start(LocationUpdateListener update) {
start();
listener = update;
}
public void stop(){
if(isRunning){
lm.removeUpdates(this);
isRunning = false;
listener = null;
}
}
public boolean hasLocation(){
if(lastLocation == null){
return false;
}
if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
return false; //stale
}
return true;
}
public boolean hasPossiblyStaleLocation(){
if(lastLocation != null){
return true;
}
return lm.getLastKnownLocation(provider)!= null;
}
public Location getLocation(){
if(lastLocation == null){
return null;
}
if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
return null; //stale
}
return lastLocation;
}
public Location getPossiblyStaleLocation(){
if(lastLocation != null){
return lastLocation;
}
return lm.getLastKnownLocation(provider);
}
public void onLocationChanged(Location newLoc) {
long now = System.currentTimeMillis();
if(listener != null){
listener.onUpdate(lastLocation, lastTime, newLoc, now);
}
lastLocation = newLoc;
lastTime = now;
}
public void onProviderDisabled(String arg0) {
}
public void onProviderEnabled(String arg0) {
}
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
The is the FallbackLocationTracker, which will track by both GPS and NETWORK, and use whatever location is more accurate.
package com.gabesechan.android.reusable.location;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
public class FallbackLocationTracker implements LocationTracker, LocationTracker.LocationUpdateListener {
private boolean isRunning;
private ProviderLocationTracker gps;
private ProviderLocationTracker net;
private LocationUpdateListener listener;
Location lastLoc;
long lastTime;
public FallbackLocationTracker(Context context) {
gps = new ProviderLocationTracker(context, ProviderLocationTracker.ProviderType.GPS);
net = new ProviderLocationTracker(context, ProviderLocationTracker.ProviderType.NETWORK);
}
public void start(){
if(isRunning){
//Already running, do nothing
return;
}
//Start both
gps.start(this);
net.start(this);
isRunning = true;
}
public void start(LocationUpdateListener update) {
start();
listener = update;
}
public void stop(){
if(isRunning){
gps.stop();
net.stop();
isRunning = false;
listener = null;
}
}
public boolean hasLocation(){
//If either has a location, use it
return gps.hasLocation() || net.hasLocation();
}
public boolean hasPossiblyStaleLocation(){
//If either has a location, use it
return gps.hasPossiblyStaleLocation() || net.hasPossiblyStaleLocation();
}
public Location getLocation(){
Location ret = gps.getLocation();
if(ret == null){
ret = net.getLocation();
}
return ret;
}
public Location getPossiblyStaleLocation(){
Location ret = gps.getPossiblyStaleLocation();
if(ret == null){
ret = net.getPossiblyStaleLocation();
}
return ret;
}
public void onUpdate(Location oldLoc, long oldTime, Location newLoc, long newTime) {
boolean update = false;
//We should update only if there is no last location, the provider is the same, or the provider is more accurate, or the old location is stale
if(lastLoc == null){
update = true;
}
else if(lastLoc != null && lastLoc.getProvider().equals(newLoc.getProvider())){
update = true;
}
else if(newLoc.getProvider().equals(LocationManager.GPS_PROVIDER)){
update = true;
}
else if (newTime - lastTime > 5 * 60 * 1000){
update = true;
}
if(update){
if(listener != null){
listener.onUpdate(lastLoc, lastTime, newLoc, newTime);
}
lastLoc = newLoc;
lastTime = newTime;
}
}
}
Since both implement the LocationTracker interface, you can easily change your mind about which one to use. To run the class in poll mode, just call start(). To run it in update mode, call start(Listener).
Also take a look at my blog post on the code
Get location of gps by -
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener()
{
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
double latitude = location.getLatitude();
double longitude = location.getLongitude();
double speed = location.getSpeed(); //spedd in meter/minute
speed = (speed*3600)/1000; // speed in km/minute Toast.makeText(GraphViews.this, "Current speed:" + location.getSpeed(),Toast.LENGTH_SHORT).show();
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
As of the second half of 2020, there is a much easier way to do this.
Excluding requesting permissions (which I will include at the bottom for devs newer to this), below is the code.
Just remember, you need to include at least this version of the library in your dependencies (in the app's build.gradle):
implementation 'com.google.android.gms:play-services-location:17.1.0'
... and of course the fine permission in your manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Kotlin (first the setup):
private val fusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(applicationContext)
}
private var cancellationTokenSource = CancellationTokenSource()
Then the main code (for FINE_LOCATION):
private fun requestCurrentLocation() {
// Check Fine permission
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Main code
val currentLocationTask: Task<Location> = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.token
)
currentLocationTask.addOnCompleteListener { task: Task<Location> ->
val result = if (task.isSuccessful) {
val result: Location = task.result
"Location (success): ${result.latitude}, ${result.longitude}"
} else {
val exception = task.exception
"Location (failure): $exception"
}
Log.d(TAG, "getCurrentLocation() result: $result")
}
} else {
// Request fine location permission (full code below).
}
If you prefer Java, it looks like this:
public class JavaVersion extends AppCompatActivity {
private final String TAG = "MainActivity";
// The Fused Location Provider provides access to location APIs.
private FusedLocationProviderClient fusedLocationClient;
// Allows class to cancel the location request if it exits the activity.
// Typically, you use one cancellation source per lifecycle.
private final CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
...
private void requestCurrentLocation() {
Log.d(TAG, "requestCurrentLocation()");
// Request permission
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Main code
Task<Location> currentLocationTask = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.getToken()
);
currentLocationTask.addOnCompleteListener((new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
String result = "";
if (task.isSuccessful()) {
// Task completed successfully
Location location = task.getResult();
result = "Location (success): " +
location.getLatitude() +
", " +
location.getLongitude();
} else {
// Task failed with an exception
Exception exception = task.getException();
result = "Exception thrown: " + exception;
}
Log.d(TAG, "getCurrentLocation() result: " + result);
}
}));
} else {
// TODO: Request fine location permission
Log.d(TAG, "Request fine location permission.");
}
}
...
}
The arguments:
PRIORITY type is self-explanatory. (Other options are PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, and PRIORITY_NO_POWER.)
CancellationToken - This allows you to cancel the request if, for instance, the user navigates away from your Activity.
Example (Kotlin):
override fun onStop() {
super.onStop()
// Cancels location request (if in flight).
cancellationTokenSource.cancel()
}
That's it.
Now, this does use the FusedLocationProviderClient which is a Google Play Services APIs.
That means this works on all Android devices with the Google Play Store (which is a lot of them). However, for devices in China without the Play Store, this won't work, so take that into account.
For developers who are a little newer to this, you need to request the fine (or coarse) location permission if the user hasn't approved it yet, so in the code above, I would request the location permission.
Below is the full code (in Kotlin).
I hope that helps (and makes your live's a little easier)!
/**
* Demonstrates how to easily get the current location via the [FusedLocationProviderClient.getCurrentLocation].
* The main code is in this class's requestCurrentLocation() method.
*/
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
// The Fused Location Provider provides access to location APIs.
private val fusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(applicationContext)
}
// Allows class to cancel the location request if it exits the activity.
// Typically, you use one cancellation source per lifecycle.
private var cancellationTokenSource = CancellationTokenSource()
// If the user denied a previous permission request, but didn't check "Don't ask again", this
// Snackbar provides an explanation for why user should approve, i.e., the additional rationale.
private val fineLocationRationalSnackbar by lazy {
Snackbar.make(
binding.container,
R.string.fine_location_permission_rationale,
Snackbar.LENGTH_LONG
).setAction(R.string.ok) {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
override fun onStop() {
super.onStop()
// Cancels location request (if in flight).
cancellationTokenSource.cancel()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
Log.d(TAG, "onRequestPermissionResult()")
if (requestCode == REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE) {
when {
grantResults.isEmpty() ->
// If user interaction was interrupted, the permission request
// is cancelled and you receive an empty array.
Log.d(TAG, "User interaction was cancelled.")
grantResults[0] == PackageManager.PERMISSION_GRANTED ->
Snackbar.make(
binding.container,
R.string.permission_approved_explanation,
Snackbar.LENGTH_LONG
)
.show()
else -> {
Snackbar.make(
binding.container,
R.string.fine_permission_denied_explanation,
Snackbar.LENGTH_LONG
)
.setAction(R.string.settings) {
// Build intent that displays the App settings screen.
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID,
null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
.show()
}
}
}
}
fun locationRequestOnClick(view: View) {
Log.d(TAG, "locationRequestOnClick()")
requestCurrentLocation()
}
/**
* Gets current location.
* Note: The code checks for permission before calling this method, that is, it's never called
* from a method with a missing permission. Also, I include a second check with my extension
* function in case devs just copy/paste this code.
*/
private fun requestCurrentLocation() {
Log.d(TAG, "requestCurrentLocation()")
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Returns a single current location fix on the device. Unlike getLastLocation() that
// returns a cached location, this method could cause active location computation on the
// device. A single fresh location will be returned if the device location can be
// determined within reasonable time (tens of seconds), otherwise null will be returned.
//
// Both arguments are required.
// PRIORITY type is self-explanatory. (Other options are PRIORITY_BALANCED_POWER_ACCURACY,
// PRIORITY_LOW_POWER, and PRIORITY_NO_POWER.)
// The second parameter, [CancellationToken] allows the activity to cancel the request
// before completion.
val currentLocationTask: Task<Location> = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.token
)
currentLocationTask.addOnCompleteListener { task: Task<Location> ->
val result = if (task.isSuccessful) {
val result: Location = task.result
"Location (success): ${result.latitude}, ${result.longitude}"
} else {
val exception = task.exception
"Location (failure): $exception"
}
Log.d(TAG, "getCurrentLocation() result: $result")
logOutputToScreen(result)
}
} else {
val provideRationale = shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
if (provideRationale) {
fineLocationRationalSnackbar.show()
} else {
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE)
}
}
}
private fun logOutputToScreen(outputString: String) {
val finalOutput = binding.outputTextView.text.toString() + "\n" + outputString
binding.outputTextView.text = finalOutput
}
companion object {
private const val TAG = "MainActivity"
private const val REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE = 34
}
}
You need to use latest/newest
GoogleApiClient Api
Basically what you need to do is:
private GoogleApiClient mGoogleApiClient;
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Then
#Override
public void onConnected(Bundle connectionHint) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));
}
}
for the most accurate and reliable location. See my post here:
https://stackoverflow.com/a/33599228/2644905
Do not use LocationListener which is not accurate and has delayed response. To be honest this is easier to implement.
Also read documentation: https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient
class MyLocation {
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled = false;
boolean network_enabled = false;
public boolean getLocation(Context context, LocationResult result) {
// I use LocationResult callback class to pass location value from
// MyLocation to user code.
locationResult = result;
if (lm == null)
lm = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
// Exceptions will be thrown if the provider is not permitted.
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
catch (Exception ex) {
}
try {
network_enabled = lm
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
catch (Exception ex) {
}
// Don't start listeners if no provider is enabled.
if (!gps_enabled && !network_enabled)
return false;
if (gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
locationListenerGps);
if (network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
locationListenerNetwork);
timer1 = new Timer();
timer1.schedule(new GetLastLocation(), 5000);
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
class GetLastLocation extends TimerTask {
#Override
public void run() {
lm.removeUpdates(locationListenerGps);
lm.removeUpdates(locationListenerNetwork);
Location net_loc = null, gps_loc = null;
if (gps_enabled)
gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (network_enabled)
net_loc = lm
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
// If there are both values, use the latest one.
if (gps_loc != null && net_loc != null) {
if (gps_loc.getTime() > net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
}
if (gps_loc != null) {
locationResult.gotLocation(gps_loc);
return;
}
if (net_loc != null) {
locationResult.gotLocation(net_loc);
return;
}
locationResult.gotLocation(null);
}
}
public static abstract class LocationResult {
public abstract void gotLocation(Location location);
}
}
I hope this will help you...
Now that Google Play locations services are here, I recommend that developers start using the new fused location provider. You will find it easier to use and more accurate. Please watch the Google I/O video Beyond the Blue Dot: New Features in Android Location by the two guys who created the new Google Play location services API.
I've been working with location APIs on a number of mobile platforms, and I think what these two guys have done is really revolutionary. It's gotten rid of a huge amount of the complexities of using the various providers. Stack Overflow is littered with questions about which provider to use, whether to use last known location, how to set other properties on the LocationManager, etc. This new API that they have built removes most of those uncertainties and makes the location services a pleasure to use.
I've written an Android app that periodically gets the location using Google Play location services and sends the location to a web server where it is stored in a database and can be viewed on Google Maps. I've written both the client software (for Android, iOS, Windows Phone and Java ME) and the server software (for ASP.NET and SQL Server or PHP and MySQL). The software is written in the native language on each platform and works properly in the background on each. Lastly, the software has the MIT License. You can find the Android client here:
https://github.com/nickfox/GpsTracker/tree/master/phoneClients/android
GoogleSamples has verbose example using latest FusedLocationProviderApi.
Unfortunately the most upvoted answers are out of date.
Follow the below examples to implement Location Services using FusedLocationProviderApi
https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates
https://github.com/googlesamples/android-play-location/blob/master/LocationUpdates/app/src/main/java/com/google/android/gms/location/sample/locationupdates/MainActivity.java
LocationManager is a class that provides in-build methods to get last know location
STEP 1 :Create a LocationManager Object as below
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
STEP 2 : Add Criteria
*Criteria is use for setting accuracy*
Criteria criteria = new Criteria();
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
criteria.setSpeedAccuracy(Criteria.ACCURACY_HIGH);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(true);
criteria.setBearingRequired(true);
criteria.setSpeedRequired(true);
}
STEP 3 :GET Avaliable Provider
Threre are two types of provider GPS and network
String provider = locationManager.getBestProvider(criteria, true);
STEP 4: Get Last Know Location
Location location = locationManager.getLastKnownLocation(provider);
STEP 5: Get Latitude and Longitude
If location object is null then dont try to call below methods
getLatitude and getLongitude is methods which returns double values
Getting location updates requires lots of bolierplate code in Android, You need to take care of
Google Play services availablity Check,
Update Google play Service if it is old or not available
Dialog Creation of GoogleApiClient and its callbacks connected,disconnected etc.
Stopping and releasing resources for location updates
Handling Location permission scenarios
Checking Location services are On or Off
Getting lastknown location is not so easy either
Fallback to last known location if not getting location after certain duration
To ease out all these steps i have created Android-EasyLocation (small android library) which will take care all this stuff and you can focus on business logic.
All you need is extend EasyLocationActivity and this
requestSingleLocationFix(easyLocationRequest);
or
requestLocationUpdates(easyLocationRequest);
Checkout sample app and steps needed here at https://github.com/akhgupta/Android-EasyLocation
I have made a project from which we can get the accurate location using Google Play Services, GPS and Network providers. This project can be found here.
Strategy in finding the best location is that first get the location from google play services if location is found then check weather it is better or not, if location found is null restart google play services and try to fetch the location from Android Location API. Register the location on change listeners and when ever the better location is found the call back returns it to the main activity.
It is very simple to use and implement in code only two classes we need to embed i.e. LocationManagerInterface and SmartLocationManager, LocationActivity is implementing the interface and using SmartLocationManager to fetch location.
/**
* Created by Syed Raza Mehdi Naqvi on 8/10/2016.
*/
public interface LocationManagerInterface {
String TAG = LocationManagerInterface.class.getSimpleName();
void locationFetched(Location mLocation, Location oldLocation, String time, String locationProvider);
}
here is the location manager class
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
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 java.text.DateFormat;
import java.util.Date;
/**
* Created by Syed Raza Mehdi Naqvi on 8/9/2016.
*/
public class SmartLocationManager implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String TAG = SmartLocationManager.class.getSimpleName();
private static final int TWO_MINUTES = 1000 * 60 * 2;
private static final int PERMISSION_REQUEST_CODE = 1000;
private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
// default value is false but user can change it
private String mLastLocationUpdateTime; // fetched location time
private String locationProvider; // source of fetched location
private Location mLastLocationFetched; // location fetched
private Location mLocationFetched; // location fetched
private Location networkLocation;
private Location gpsLocation;
private int mLocationPiority;
private long mLocationFetchInterval;
private long mFastestLocationFetchInterval;
private Context mContext; // application context
private Activity mActivity; // activity context
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private LocationManagerInterface mLocationManagerInterface;
private android.location.LocationManager locationManager;
private android.location.LocationListener locationListener;
boolean isGPSEnabled;
boolean isNetworkEnabled;
private int mProviderType;
public static final int NETWORK_PROVIDER = 1;
public static final int ALL_PROVIDERS = 0;
public static final int GPS_PROVIDER = 2;
// private final double STANDARD_LOCATION_ACCURACY = 100.0;
// private final double STANDARD_LOCATION_SEED_LIMIT = 6.95;
public static final int LOCATION_PROVIDER_ALL_RESTICTION = 1;
public static final int LOCATION_PROVIDER_RESTRICTION_NONE = 0;
public static final int LOCATION_PROVIDER_GPS_ONLY_RESTICTION = 2;
public static final int LOCATION_PROVIDER_NETWORK_ONLY_RESTICTION = 3;
private int mForceNetworkProviders = 0;
public SmartLocationManager(Context context, Activity activity, LocationManagerInterface locationInterface, int providerType, int locationPiority, long locationFetchInterval, long fastestLocationFetchInterval, int forceNetworkProviders) {
mContext = context;
mActivity = activity;
mProviderType = providerType;
mLocationPiority = locationPiority;
mForceNetworkProviders = forceNetworkProviders;
mLocationFetchInterval = locationFetchInterval;
mFastestLocationFetchInterval = fastestLocationFetchInterval;
mLocationManagerInterface = locationInterface;
initSmartLocationManager();
}
public void initSmartLocationManager() {
// 1) ask for permission for Android 6 above to avoid crash
// 2) check if gps is available
// 3) get location using awesome strategy
askLocationPermission(); // for android version 6 above
checkNetworkProviderEnable(mForceNetworkProviders); //
if (isGooglePlayServicesAvailable()) // if googleplay services available
initLocationObjts(); // init obj for google play service and start fetching location
else
getLocationUsingAndroidAPI(); // otherwise get location using Android API
}
private void initLocationObjts() {
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(mLocationPiority)
.setInterval(mLocationFetchInterval) // 10 seconds, in milliseconds
.setFastestInterval(mFastestLocationFetchInterval); // 1 second, in milliseconds
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
startLocationFetching(); // connect google play services to fetch location
}
#Override
public void onConnected(Bundle connectionHint) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
startLocationUpdates();
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
getLocationUsingAndroidAPI();
} else {
setNewLocation(getBetterLocation(location, mLocationFetched), mLocationFetched);
}
}
#Override
public void onLocationChanged(Location location) {
if (location == null) {
getLastKnownLocation();
} else {
setNewLocation(getBetterLocation(location, mLocationFetched), mLocationFetched);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection suspended");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(mActivity, CONNECTION_FAILURE_RESOLUTION_REQUEST); // Start an Activity that tries to resolve the error
getLocationUsingAndroidAPI(); // try to get location using Android API locationManager
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
private void setNewLocation(Location location, Location oldLocation) {
if (location != null) {
mLastLocationFetched = oldLocation;
mLocationFetched = location;
mLastLocationUpdateTime = DateFormat.getTimeInstance().format(new Date());
locationProvider = location.getProvider();
mLocationManagerInterface.locationFetched(location, mLastLocationFetched, mLastLocationUpdateTime, location.getProvider());
}
}
private void getLocationUsingAndroidAPI() {
// Acquire a reference to the system Location Manager
locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
setLocationListner();
captureLocation();
}
public void captureLocation() {
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
if (mProviderType == SmartLocationManager.GPS_PROVIDER) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
} else if (mProviderType == SmartLocationManager.NETWORK_PROVIDER) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
} else {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
private void setLocationListner() {
// Define a listener that responds to location updates
locationListener = new android.location.LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
if (location == null) {
getLastKnownLocation();
} else {
setNewLocation(getBetterLocation(location, mLocationFetched), mLocationFetched);
// if (isLocationAccurate(location) && location.getAccuracy() < STANDARD_LOCATION_ACCURACY && location.getSpeed() < STANDARD_LOCATION_SEED_LIMIT) {// no use of this if
// setNewLocation(getBetterLocation(location, mLocationFetched), mLocationFetched);
// } else {
// setNewLocation(getBetterLocation(location, mLocationFetched), mLocationFetched);
// }
}
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
};
}
public Location getAccurateLocation() {
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
try {
gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Location newLocalGPS, newLocalNetwork;
if (gpsLocation != null || networkLocation != null) {
newLocalGPS = getBetterLocation(mLocationFetched, gpsLocation);
newLocalNetwork = getBetterLocation(mLocationFetched, networkLocation);
setNewLocation(getBetterLocation(newLocalGPS, newLocalNetwork), mLocationFetched);
}
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
return mLocationFetched;
}
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
public void startLocationFetching() {
mGoogleApiClient.connect();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
}
}
public void pauseLocationFetching() {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
public void abortLocationFetching() {
mGoogleApiClient.disconnect();
// Remove the listener you previously added
if (locationManager != null && locationListener != null) {
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
locationManager.removeUpdates(locationListener);
locationManager = null;
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
}
}
public void resetLocation() {
mLocationFetched = null;
mLastLocationFetched = null;
networkLocation = null;
gpsLocation = null;
}
// Android M Permission check
public void askLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
) {
if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.ACCESS_COARSE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.ACCESS_FINE_LOCATION)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setMessage("Please allow all permissions in App Settings for additional functionality.")
.setCancelable(false)
.setPositiveButton("Allow", new DialogInterface.OnClickListener() {
public void onClick(#SuppressWarnings("unused") final DialogInterface dialog, #SuppressWarnings("unused") final int id) {
Toast.makeText(mContext, "Welcome", Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton("Deny", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, #SuppressWarnings("unused") final int id) {
mActivity.finish();
}
});
final AlertDialog alert = builder.create();
alert.show();
} else
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION
, Manifest.permission.ACCESS_FINE_LOCATION
}, PERMISSION_REQUEST_CODE);
}
}
}
public void checkNetworkProviderEnable(int enforceActive) {
locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
buildAlertMessageTurnOnLocationProviders("Your location providers seems to be disabled, please enable it", "OK", "Cancel");
} else if (!isGPSEnabled && mForceNetworkProviders == LOCATION_PROVIDER_GPS_ONLY_RESTICTION) {
buildAlertMessageTurnOnLocationProviders("Your GPS seems to be disabled, please enable it", "OK", "Cancel");
} else if (!isNetworkEnabled && mForceNetworkProviders == LOCATION_PROVIDER_NETWORK_ONLY_RESTICTION) {
buildAlertMessageTurnOnLocationProviders("Your Network location provider seems to be disabled, please enable it", "OK", "Cancel");
}
// getting network status
if (!isGPSEnabled && !isNetworkEnabled) {
Toast.makeText(mContext, "Location can't be fetched!", Toast.LENGTH_SHORT).show(); // show alert
mActivity.finish();
}
}
private void buildAlertMessageTurnOnLocationProviders(String message, String positiveButtonText, String negativeButtonText) {
final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton(positiveButtonText, new DialogInterface.OnClickListener() {
public void onClick(#SuppressWarnings("unused") final DialogInterface dialog, #SuppressWarnings("unused") final int id) {
Intent mIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(mIntent);
}
})
.setNegativeButton(negativeButtonText, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, #SuppressWarnings("unused") final int id) {
mActivity.finish();
}
});
final AlertDialog alert = builder.create();
alert.show();
}
public Location getLastKnownLocation() {
locationProvider = LocationManager.NETWORK_PROVIDER;
Location lastKnownLocation = null;
// Or use LocationManager.GPS_PROVIDER
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return lastKnownLocation;
}
try {
lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
return lastKnownLocation;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return lastKnownLocation;
}
public boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
if (status == ConnectionResult.SUCCESS) {
return true;
} else {
return false;
}
}
/**
* Determines whether one Location reading is better than the current Location fix
*
* #param location The new Location that you want to evaluate
* #param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected Location getBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return location;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return location;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return currentBestLocation;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return location;
} else if (isNewer && !isLessAccurate) {
return location;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return location;
}
return currentBestLocation;
}
/**
* Checks whether two providers are the same
*/
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
public boolean isLocationAccurate(Location location) {
if (location.hasAccuracy()) {
return true;
} else {
return false;
}
}
public Location getStaleLocation() {
if (mLastLocationFetched != null) {
return mLastLocationFetched;
}
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
if (mProviderType == SmartLocationManager.GPS_PROVIDER) {
return locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} else if (mProviderType == SmartLocationManager.NETWORK_PROVIDER) {
return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
} else {
return getBetterLocation(locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER), locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER));
}
}
}
we can use it with activity or a fragment, here i am using it with activity
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
import com.example.raza.locationaware.location.LocationManagerInterface;
import com.example.raza.locationaware.location.SmartLocationManager;
import com.google.android.gms.location.LocationRequest;
public class LocationActivity extends AppCompatActivity implements LocationManagerInterface {
public static final String TAG = LocationActivity.class.getSimpleName();
SmartLocationManager mLocationManager;
TextView mLocalTV, mLocationProviderTV, mlocationTimeTV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
mLocationManager = new SmartLocationManager(getApplicationContext(), this, this, SmartLocationManager.ALL_PROVIDERS, LocationRequest.PRIORITY_HIGH_ACCURACY, 10 * 1000, 1 * 1000, SmartLocationManager.LOCATION_PROVIDER_RESTRICTION_NONE); // init location manager
mLocalTV = (TextView) findViewById(R.id.locationDisplayTV);
mLocationProviderTV = (TextView) findViewById(R.id.locationProviderTV);
mlocationTimeTV = (TextView) findViewById(R.id.locationTimeFetchedTV);
}
protected void onStart() {
super.onStart();
mLocationManager.startLocationFetching();
}
protected void onStop() {
super.onStop();
mLocationManager.abortLocationFetching();
}
#Override
protected void onPause() {
super.onPause();
mLocationManager.pauseLocationFetching();
}
#Override
public void locationFetched(Location mLocal, Location oldLocation, String time, String locationProvider) {
Toast.makeText(getApplication(), "Lat : " + mLocal.getLatitude() + " Lng : " + mLocal.getLongitude(), Toast.LENGTH_LONG).show();
mLocalTV.setText("Lat : " + mLocal.getLatitude() + " Lng : " + mLocal.getLongitude());
mLocationProviderTV.setText(locationProvider);
mlocationTimeTV.setText(time);
}
}
Hope it helps, if you can suggest any improvement kindly post it on git. Thanks.
For just location checking you can use following code. You can put it in your onStart() of main activity and display alert dialog if return is false.
private boolean isLocationAccurate()
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
{
String provider = Settings.Secure
.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (provider != null && !provider.contains("gps"))
{
return false;
}
}
else
{
try
{
int status = Settings.Secure
.getInt(this.getContentResolver(), Settings.Secure.LOCATION_MODE);
if (status != Settings.Secure.LOCATION_MODE_HIGH_ACCURACY)
{
return false;
}
}
catch (Settings.SettingNotFoundException e)
{
Log.e(TAG, e.getMessage());
}
}
return true;
}
I have got very accurate location using FusedLocationProviderClient
(Google Play services required)
Permissions Required
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
Dependency
'com.google.android.gms:play-services-location:15.0.0'
Kotlin Code
val client = FusedLocationProviderClient(this)
val location = client.lastLocation
location.addOnCompleteListener {
// this is a lambda expression and we get an 'it' iterator to access the 'result'
// it.result.latitude gives the latitude
// it.result.longitude gives the longitude
val geocoder = Geocoder(applicationContext, Locale.getDefault())
val address = geocoder.getFromLocation(it.result.latitude, it.result.longitude, 1)
if (address != null && address.size > 0) {
// Get the current city
city = address[0].locality
}
}
location.addOnFailureListener {
// Some error in getting the location, let's log it
Log.d("xtraces", it.message)
}
Since September 23, 2020 play-services-location version 17.1.0 includes FusedLocationProviderClient.getCurrentLocation() method which is the recommended and straightforward way to get the current location:
Returns a single current location fix on the device. Unlike getLastLocation() that returns a cached location, this method could cause active location computation on the device. A single fresh location will be returned if the device location can be determined within reasonable time (tens of seconds), otherwise null will be returned.
For a detailed example take a look at codingjeremy's answer and an official Android location sample on GitHub - Current Location (Kotlin).
If you are creating new location projects for Android you should use the new Google Play location services. It is much more accurate and much simpler to use.
I have been working on an open source GPS tracker project, GpsTracker, for several years. I recently updated it to handle periodic updates from Android, iOS, Windows Phone and Java ME cell phones. It is fully functional and does what you need and has the MIT License.
The Android project within GpsTracker uses the new Google Play services and there are also two server stacks (ASP.NET and PHP) to allow you to track those phones.
April 2020
Full steps to get current location, and avoid Last Known Location nullability.
According to official documentation, Last Known Location could be Null in case of:
Location is turned off in the device settings. As it clears the
cache.
The device never recorded its location. (New device)
Google Play services on the device has restarted.
In this case, you should requestLocationUpdates and receive the new location on the LocationCallback.
By the following steps your last known Location never null.
Pre-requisite:
EasyPermission library
Step 1:
In manifest file add this permission
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Step 2:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Create location callback when it's ready.
createLocationCallback()
//createing location request, how mant request would be requested.
createLocationRequest()
//Build check request location setting request
buildLocationSettingsRequest()
//FusedLocationApiClient which includes location
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
//Location setting client
mSettingsClient = LocationServices.getSettingsClient(this)
//Check if you have ACCESS_FINE_LOCATION permission
if (!EasyPermissions.hasPermissions(
this#MainActivity,
Manifest.permission.ACCESS_FINE_LOCATION)) {
requestPermissionsRequired()
}
else{
//If you have the permission we should check location is opened or not
checkLocationIsTurnedOn()
}
}
Step 3:
Create required functions to be called in onCreate()
private fun requestPermissionsRequired() {
EasyPermissions.requestPermissions(
this,
getString(R.string.location_is_required_msg),
LOCATION_REQUEST,
Manifest.permission.ACCESS_FINE_LOCATION
)
}
private fun createLocationCallback() {
//Here the location will be updated, when we could access the location we got result on this callback.
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
mCurrentLocation = locationResult.lastLocation
}
}
}
private fun buildLocationSettingsRequest() {
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest!!)
mLocationSettingsRequest = builder.build()
builder.setAlwaysShow(true)
}
private fun createLocationRequest() {
mLocationRequest = LocationRequest.create()
mLocationRequest!!.interval = 0
mLocationRequest!!.fastestInterval = 0
mLocationRequest!!.numUpdates = 1
mLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
public fun checkLocationIsTurnedOn() { // Begin by checking if the device has the necessary location settings.
mSettingsClient!!.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(this) {
Log.i(TAG, "All location settings are satisfied.")
startLocationUpdates()
}
.addOnFailureListener(this) { e ->
val statusCode = (e as ApiException).statusCode
when (statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
try {
val rae = e as ResolvableApiException
rae.startResolutionForResult(this#MainActivity, LOCATION_IS_OPENED_CODE)
} catch (sie: IntentSender.SendIntentException) {
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
mRequestingLocationUpdates = false
}
}
}
}
private fun startLocationUpdates() {
mFusedLocationClient!!.requestLocationUpdates(
mLocationRequest,
mLocationCallback, null
)
}
Step 4:
Handle callbacks in onActivityResult() after ensuring the location is opened or the user accepts to open it in.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
LOCATION_IS_OPENED_CODE -> {
if (resultCode == AppCompatActivity.RESULT_OK) {
Log.d(TAG, "Location result is OK")
} else {
activity?.finish()
}
}
}
Step 5:
Get last known location from FusedClientApi
override fun onMapReady(map: GoogleMap) {
mMap = map
mFusedLocationClient.lastLocation.addOnSuccessListener {
if(it!=null){
locateUserInMap(it)
}
}
}
private fun locateUserInMap(location: Location) {
showLocationSafetyInformation()
if(mMap!=null){
val currentLocation = LatLng(location.latitude,location.longitude )
addMarker(currentLocation)
}
}
private fun addMarker(currentLocation: LatLng) {
val cameraUpdate = CameraUpdateFactory.newLatLng(currentLocation)
mMap?.clear()
mMap?.addMarker(
MarkerOptions().position(currentLocation)
.title("Current Location")
)
mMap?.moveCamera(cameraUpdate)
mMap?.animateCamera(cameraUpdate)
mMap?.setMinZoomPreference(14.0f);
}
I hope this would help.
Happy Coding 🤓
I have published a small library that can make it easy to get location data in Android, it even takes care of Android M runtime permissions.
You might check it out here: https://github.com/julioromano/RxLocation and use it or its source code as examples for your implementation.
Simple Find Write Code in On Location Method
public void onLocationChanged(Location location) {
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(18));
PolylineOptions pOptions = new PolylineOptions()
.width(5)
.color(Color.GREEN)
.geodesic(true);
for (int z = 0; z < routePoints.size(); z++) {
LatLng point = routePoints.get(z);
pOptions.add(point);
}
line = mMap.addPolyline(pOptions);
routePoints.add(latLng);
}
Best way to fetch location is below
// put dependancy
implementation 'com.google.android.gms:play-services-location:11.0.4'
// PUT permissions in Menifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
// create a Java file as below
public class SingleShotLocationProvider {
public static interface LocationCallback {
public void onNewLocationAvailable(GPSCoordinates location);
}
// calls back to calling thread, note this is for low grain: if you want higher precision, swap the
// contents of the else and if. Also be sure to check gps permission/settings are allowed.
// call usually takes <10ms
public static void requestSingleUpdate(final Context context, final LocationCallback callback) {
final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isNetworkEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}, null);
} else {
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
}, null);
}
}
}
// consider returning Location instead of this dummy wrapper class
public static class GPSCoordinates {
public float longitude = -1;
public float latitude = -1;
public GPSCoordinates(float theLatitude, float theLongitude) {
longitude = theLongitude;
latitude = theLatitude;
}
public GPSCoordinates(double theLatitude, double theLongitude) {
longitude = (float) theLongitude;
latitude = (float) theLatitude;
}
}
}
// FILE FINISHED
// FETCH LOCATION FROM ACTIVITY AS BELOW
public void getLocation(Context context) {
MyApplication.log(LOG_TAG, "getLocation() ");
SingleShotLocationProvider.requestSingleUpdate(context,
new SingleShotLocationProvider.LocationCallback() {
#Override
public void onNewLocationAvailable(SingleShotLocationProvider.GPSCoordinates loc) {
location = loc;
MyApplication.log(LOG_TAG, "getLocation() LAT: " + location.latitude + ", LON: " + location.longitude);
}
});
}
Edit 2022: Don't use this as that lib has memory leaks and is not support/updated any more.
I will recommend using Smart Location Library
Very simple to use and it wraps the location logic nicely.
For starting the location service:
SmartLocation.with(context).location()
.start(new OnLocationUpdatedListener() { ... });
If you just want to get a single location (not periodic) you can just use the oneFix modifier. Example:
SmartLocation.with(context).location()
.oneFix()
.start(new OnLocationUpdatedListener() { ... });

Categories

Resources