Monitor if GPS enabled - android

I wish to add listener if GPS enabled or not.
This code determine if it enabled:
private fun locationEnabled(): Boolean {
val manager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
return manager.isProviderEnabled(LocationManager.GPS_PROVIDER)
}
I wish to listen to this change, so I tried:
val mLocationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
val mGnssStatusCallback = object : GnssStatus.Callback() {
override fun onStarted() {
super.onStarted()
Log.d(TAG,".onStarted()")
}
override fun onStopped() {
super.onStopped()
Log.d(TAG,".onStopped()")
}
}
var pop = mLocationManager.registerGnssStatusCallback(mGnssStatusCallback)
But its not giving the result I need, it not consistent with if it enabled/disabled.

Related

Cannot stop Fused Location Provider using removeLocationUpdates()

I have an activity that is receiving the user location every X seconds. When the user location is within the radius of 15 meters from a specific point, I want the Location Provider to stop updating the user location and to start a new activity.
I have the following method to stop location updates:
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
I call stopLocationUpdates() in both onPause() and onDestroy() methods. I've tried to call it inside the for each location cicle, when the case distance < 15 is verified. None of this seems to work.
I am trying to call finish() to finish the current activity and by using the Logcat I see that the location keeps updating, although the activity is finished.
Plus, the new activity (ExerciseActivity) keeps launching in loop.
Please, let me know how I can stop this. Thank you in advance.
I leave here the major parts of the code of this activity:
class MapActivity : AppCompatActivity() {
private val requestPermissionsRequestCode = 1
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback
private lateinit var locationRequest: LocationRequest
private var allCheckpoints: List<CheckpointResult> = ArrayList()
private val mAdapterNextCheckpoints = NextCheckpointAdapter()
private var nextCheckpoints: ArrayList<CheckpointResult> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map)
requestPermissionsIfNecessary(arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.INTERNET
))
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
if (location != null) {
mUserMarker.position = GeoPoint(location.latitude, location.longitude)
mUserMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
mUserMarker.title = getString(R.string.your_position)
map.overlays.add(mUserMarker)
map.controller.setCenter(mUserMarker.position)
}
}
startLocationUpdates()
}
private fun startLocationUpdates() {
locationRequest = create()
locationRequest.interval = 4000
locationRequest.priority = Priority.PRIORITY_HIGH_ACCURACY
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
mUserMarker.position = GeoPoint(location.latitude, location.longitude)
mUserMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
mUserMarker.title = getString(R.string.your_position)
map.overlays.add(mUserMarker)
mAdapterNextCheckpoints
if (nextCheckpoints.isNotEmpty()) {
for (checkpoint in nextCheckpoints) {
val results = FloatArray(3)
Location.distanceBetween(checkpoint.latitude,
checkpoint.longitude,
location.latitude,
location.longitude, results)
val distance = results[0]
Log.d("Distance: ", distance.toString())
if (distance <= 15) {
//stopLocationUpdates()
val i = Intent(this#MapActivity, ExerciseActivity::class.java)
i.putExtra("exerciseId", checkpoint.exercise.exerciseId)
startActivity(i)
finish()
}
}
}
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper())
}
override fun onResume() {
super.onResume()
startLocationUpdates()
}
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
override fun onDestroy() {
super.onDestroy()
stopLocationUpdates()
}
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
}
Try removing startLocationUpdates() call inside onCreate() and I hope it will get you to work.
Explenation:
You are calling startLocationUpdates() method in both onCreate() and onResume() methods. So it will make two callbacks which you store the latest inside locationCallback. But you loose the first callback created when onCreate() is called. So when you call fusedLocationClient .removeLocationUpdates(locationCallback), you just remove one of the callbacks!

Why I can only retrieve current location when already having permission?

I want to handle something in my ViewModel whenever the current location retrieved. But it didn't work at the first time I start the app and approve the permission. Only be able to see some logs after I close and start the app again.
init {
viewModelScope.launch {
locationRepository.location.collect {
Log.d(TAG, it.toString())
My repository to connect the location data source as you can see
class LocationRepositoryImpl #Inject constructor(
private val dataSource: LocationDataSource,
#ApplicationScope private val externalScope: CoroutineScope
) : LocationRepository {
override val location: Flow<MapLocation> = dataSource.locationSource
.shareIn(
scope = externalScope,
started = WhileSubscribed()
And the final is LocationDataSource where I put the logic to get the current location.
class LocationDataSource #Inject constructor(
private val client: FusedLocationProviderClient
) {
val locationSource: Flow<MapLocation> = callbackFlow {
val request = LocationRequest.create().apply {
interval = TimeUnit.SECONDS.toMillis(4)
fastestInterval = TimeUnit.SECONDS.toMillis(4)
priority = Priority.PRIORITY_HIGH_ACCURACY
}
val callBack = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
super.onLocationResult(result)
result.lastLocation?.let {
trySend(it.asModel())
}
}
}
//Subscribe to location changes.
client.requestLocationUpdates(request, callBack, Looper.getMainLooper())
awaitClose { client.removeLocationUpdates(callBack) }
The cause is I still did use the onPermissionResult() in my fragment, so after switch to the new requestPermissionLauncher = registerForActivityResult, and call onForegroundPermissionApproved() instead of in init of ViewModel, after approve the location permission. Everything work properly.

FusedLocationProvider rapid updates when Google Maps are turned on

I'm using FusedLocationProvider in my app and I noticed that when my app is in the background and I start some other app that contains Google Map my original app starts receiving location updates extremely fast (like 1 update per second) despite setting up the fastest interval.
I know that I should unregister when going to background etc but this is not the case here.
Any ideas why this might happen or where I can report it to Google?
This is the activity I start it from (I've removed couple of permissions check just for the visibility)
The full repo can be found here
class MainActivity : AppCompatActivity() {
private val locationController by lazy { LocationController.getInstance(applicationContext) }
lateinit var button: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button = findViewById(R.id.button)
button.setOnClickListener {
if (locationController.isStarted) {
locationController.stop()
button.text = "START LOCATION UPDATES"
} else {
locationController.start()
button.text = "STOP LOCATION UPDATED"
}
}
}
And the LocationController looks like this:
class LocationController(context: Context) {
companion object {
#Volatile private var INSTANCE: LocationController? = null
fun getInstance(context: Context): LocationController {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: LocationController(context).also { INSTANCE = it }
}
}
}
private val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
private val locationRequest by lazy {
LocationRequest.create()
.setInterval(INTERVAL_MILLIS)
.setFastestInterval(FASTEST_INTERVAL_MILLIS)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
}
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
Log.d("boom", "onLocationResult! ${locationResult.lastLocation}")
}
override fun onLocationAvailability(locationAvailability: LocationAvailability) {
super.onLocationAvailability(locationAvailability)
}
}
var isStarted: Boolean = false
#SuppressLint("MissingPermission")
fun start() {
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
.addOnSuccessListener {
Log.d("boom", "requestLocationUpdates success!")
}
isStarted = true
}
fun stop() {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
.addOnSuccessListener {
Log.d("boom", "removeLocationUpdates success!")
}
isStarted = false
}
The constant values I experience it with are:
const val INTERVAL_MILLIS = 30_000L
const val FASTEST_INTERVAL_MILLIS = 10_000L

Geofences events just called with fake gps app, in real gps it is not called

I am creating a foreground service that creates a geofence area in user local, and when the user exit from the geofence area i create another geofence area, again in user local.
I have a low RAM Quantity so i tested on my phone android 9, and with the fake gps app, it works fine, but when i use the real gps don't. I defined the high accuracy on android phone configuration and still doesn't work. Finally i had decided to put fire on my pc and use the emulator to control the phone location, and yet doesn't work. Not even de initial trigger is called.
So what is the difference between the fake gps and de real gps that defines if my code will work or not
class LocationForegroundService : LifecycleService() {
private lateinit var geofencingClient: GeofencingClient
private lateinit var locationClient: FusedLocationProviderClient
private lateinit var pendingBroadcastIntent: PendingIntent
private var geoId = ""
companion object {
private var count = 0
private var geoAlreadyInitialized = false
private const val TRACKING_CHANNEL = "tracking_channel"
private const val TRACKING_NOTIFICATION_ID = 1
private lateinit var mContext: Context
private val exitFromGeofence = MutableLiveData(false)
var isTrackingRider: Boolean = false
private set
fun startService(context: Context) {
mContext = context
val startIntent = Intent(context, LocationForegroundService::class.java)
ContextCompat.startForegroundService(context, startIntent)
isTrackingRider = true
}
fun stopService(context: Context) {
val stopIntent = Intent(context, LocationForegroundService::class.java)
context.stopService(stopIntent)
isTrackingRider = false
}
class GeofenceReceiver : BroadcastReceiver() {
#SuppressLint("MissingPermission")
override fun onReceive(context: Context?, intent: Intent?) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
return
}
when (geofencingEvent.geofenceTransition) {
GEOFENCE_TRANSITION_EXIT -> {
geofencingEvent.triggeringGeofences.forEach {
context?.showShortToast("EXIT geo ${it.requestId}")
}
exitFromGeofence.value = true
}
GEOFENCE_TRANSITION_ENTER -> {
geofencingEvent.triggeringGeofences.forEach {
context?.showShortToast("Enter geo ${it.requestId}")
}
}
GEOFENCE_TRANSITION_DWELL -> {
context?.showShortToast("dwell geo blabla")
}
}
}
}
}
override fun onCreate() {
super.onCreate()
locationClient = LocationServices.getFusedLocationProviderClient(mContext)
geofencingClient = LocationServices.getGeofencingClient(mContext)
val intent = Intent(mContext, GeofenceReceiver::class.java)
pendingBroadcastIntent = PendingIntent.getBroadcast(
mContext,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
createObservers()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
createNotificationChannel()
// ... creates notification for foreground
updateLocation()
return START_NOT_STICKY
}
#SuppressLint("MissingPermission")
private fun createNewGeofence(location: Location) {
removeActualGeofence()
geoId = "geo_id_$count"
val geofence = getGeofence(location)
val geofencingRequest = getGeofenceRequest(geofence)
initGeofence(geofencingRequest)
}
#SuppressLint("MissingPermission")
private fun initGeofence(geofencingRequest: GeofencingRequest) {
geofencingClient.addGeofences(geofencingRequest, pendingBroadcastIntent)
.addOnSuccessListener {
geoAlreadyInitialized = true
}
.addOnFailureListener {
}
}
#SuppressLint("MissingPermission")
private fun updateLocation() {
locationClient.lastLocation.addOnSuccessListener { location ->
createNewGeofence(location)
}
}
private fun getGeofenceRequest(geofence: Geofence) =
GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build()
private fun getGeofence(location: Location) = Builder()
.setCircularRegion(location.latitude, location.longitude, 200F)
.setRequestId(geoId)
.setTransitionTypes(GEOFENCE_TRANSITION_ENTER or GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(NEVER_EXPIRE)
.setNotificationResponsiveness(0)
.build()
private fun removeActualGeofence() {
geofencingClient.removeGeofences(mutableListOf(geoId))
.addOnFailureListener {}
.addOnSuccessListener {
if (geoAlreadyInitialized) count++
}
}
private fun createObservers() {
exitFromGeofence.observe(this) {
updateLocation()
}
}
private fun createNotificationChannel() {
// ...create notification channel
}
}
The problem is that i was trying to use locationClient.lastLocation to get the user actual location, and when there was no last location to get it fail on create the geofence o the right place, just when i use the fake gps app the phone recorded a location and it works, so i changed to use requestLocationUpdates to get the actual locale.

Get location android Kotlin

I recently added get location function. When I try to show longitude and latitude, it returns zero.
This my LocationListener class:
inner class MylocationListener: LocationListener {
constructor():super(){
mylocation= Location("me")
mylocation!!.longitude
mylocation!!.latitude
}
override fun onLocationChanged(location: Location?) {
mylocation=location
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {}
override fun onProviderEnabled(p0: String?) {}
override fun onProviderDisabled(p0: String?) {}
}
And this my GetUserLocation function:
fun GetUserLocation(){
var mylocation= MylocationListener()
var locationManager=getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0.1f,mylocation)
}
And this my function to return my longitude and latitude:
fun getLoction (view: View){
prgDialog!!.show();
GetUserLocation()
button.setTextColor(getResources().getColor(R.color.green));
textView.text = mylocation!!.latitude.toFloat().toString()
Toast.makeText(this, mylocation!!.latitude.toFloat().toString(), Toast.LENGTH_LONG).show()
Toast.makeText(this, mylocation!!.longitude.toFloat().toString(), Toast.LENGTH_LONG).show()
prgDialog!!.hide()
}
In 2019 Best Offical Solution in Kotlin
Google API Client/FusedLocationApi are deprecated and Location Manager is not useful at all.
So Google prefer Fused Location Provider Using the Google Play services location APIs
"FusedLocationProviderClient" is used to get location and its better way for battery saving and accuracy
Here is sample code in kotlin to get the last known location /one-time location( equivalent to the current location)
// declare a global variable of FusedLocationProviderClient
private lateinit var fusedLocationClient: FusedLocationProviderClient
// in onCreate() initialize FusedLocationProviderClient
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
/**
* call this method for receive location
* get location and give callback when successfully retrieve
* function itself check location permission before access related methods
*
*/
fun getLastKnownLocation() {
fusedLocationClient.lastLocation
.addOnSuccessListener { location->
if (location != null) {
// use your location object
// get latitude , longitude and other info from this
}
}
}
If your app can continuously track the location then you have to receive Receive location updates
Check the sample for that in kotlin
// declare a global variable FusedLocationProviderClient
private lateinit var fusedLocationClient: FusedLocationProviderClient
// in onCreate() initialize FusedLocationProviderClient
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
// globally declare LocationRequest
private lateinit var locationRequest: LocationRequest
// globally declare LocationCallback
private lateinit var locationCallback: LocationCallback
/**
* call this method in onCreate
* onLocationResult call when location is changed
*/
private fun getLocationUpdates()
{
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
locationRequest = LocationRequest()
locationRequest.interval = 50000
locationRequest.fastestInterval = 50000
locationRequest.smallestDisplacement = 170f // 170 m = 0.1 mile
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //set according to your app function
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
if (locationResult.locations.isNotEmpty()) {
// get latest location
val location =
locationResult.lastLocation
// use your location object
// get latitude , longitude and other info from this
}
}
}
}
//start location updates
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
null /* Looper */
)
}
// stop location updates
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
// stop receiving location update when activity not visible/foreground
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
// start receiving location update when activity visible/foreground
override fun onResume() {
super.onResume()
startLocationUpdates()
}
Make sure you take care about Mainfaist permission and runtime permission for location
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
and for Gradle add this
implementation 'com.google.android.gms:play-services-location:17.0.0'
For more details follow these official documents
https://developer.android.com/training/location/retrieve-current
https://developer.android.com/training/location/receive-location-updates
https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient
When GetUserLocation returns, locationManager goes out of scope and presumably is destroyed, preventing onLocationChanged from being called and providing updates.
Also, you've defined mylocation inside of GetUserLocation so it also goes out of scope and further kills any chance or your getting an update.
You have not shown where and how the outer mylocation is declared (outside of GetUserLocation), but how ever it is declared, it is being shadowed by the one inside of GetUserLocation. So you aren't getting much.
Here is an example of how you might do it. (The variable thetext is defined within the layout xml and accessed with Kotlin extensions.)
// in the android manifest
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
// allow these through Appliation Manager if necessary
// inside a basic activity
private var locationManager : LocationManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
// Create persistent LocationManager reference
locationManager = getSystemService(LOCATION_SERVICE) as LocationManager?
fab.setOnClickListener { view ->
try {
// Request location updates
locationManager?.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0L, 0f, locationListener)
} catch(ex: SecurityException) {
Log.d("myTag", "Security Exception, no location available")
}
}
}
//define the listener
private val locationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
thetext.text = ("" + location.longitude + ":" + location.latitude)
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}
I know it's late, but now Google has made it simpler to use. In the developer site, it says that you need to create a Client:
private lateinit var fusedLocationClient: FusedLocationProviderClient
Then onCreate get the provider:
override fun onCreate(savedInstanceState: Bundle?) {
// ...
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}
And finally, to get your last location just call:
//Don't forget to ask for permissions for ACCESS_COARSE_LOCATION
//and ACCESS_FINE_LOCATION
#SuppressLint("MissingPermission")
private fun obtieneLocalizacion(){
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
latitude = location?.latitude
longitude = location?.longitude
}
}
*Tested with this implementation for location (Setup in your app gradle file)
implementation 'com.google.android.gms:play-services-location:15.0.1'
For more info, check this link:
Obtain last location
Get location with address in android kotlin
Add this line in dependencies
implementation 'com.google.android.gms:play-services-location:17.0.0'
Add this in AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Copy this below code in your class
class MainActivity : AppCompatActivity() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
/*Check location*/
checkLocation()
}
private fun checkLocation(){
val manager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
showAlertLocation()
}
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
getLocationUpdates()
}
private fun showAlertLocation() {
val dialog = AlertDialog.Builder(this)
dialog.setMessage("Your location settings is set to Off, Please enable location to use this application")
dialog.setPositiveButton("Settings") { _, _ ->
val myIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(myIntent)
}
dialog.setNegativeButton("Cancel") { _, _ ->
finish()
}
dialog.setCancelable(false)
dialog.show()
}
private fun getLocationUpdates() {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
locationRequest = LocationRequest()
locationRequest.interval = 50000
locationRequest.fastestInterval = 50000
locationRequest.smallestDisplacement = 170f //170 m = 0.1 mile
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //according to your app
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
if (locationResult.locations.isNotEmpty()) {
/*val location = locationResult.lastLocation
Log.e("location", location.toString())*/
val addresses: List<Address>?
val geoCoder = Geocoder(applicationContext, Locale.getDefault())
addresses = geoCoder.getFromLocation(
locationResult.lastLocation.latitude,
locationResult.lastLocation.longitude,
1
)
if (addresses != null && addresses.isNotEmpty()) {
val address: String = addresses[0].getAddressLine(0)
val city: String = addresses[0].locality
val state: String = addresses[0].adminArea
val country: String = addresses[0].countryName
val postalCode: String = addresses[0].postalCode
val knownName: String = addresses[0].featureName
Log.e("location", "$address $city $state $postalCode $country $knownName")
}
}
}
}
}
// Start location updates
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
null /* Looper */
)
}
// Stop location updates
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
// Stop receiving location update when activity not visible/foreground
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
// Start receiving location update when activity visible/foreground
override fun onResume() {
super.onResume()
startLocationUpdates()
}}
Run your code and check the log, Happy Coding
I read many of answers but question is get only last known location.
With receiver it continuously send latitude and longitude
I have solution for this in kotlin..
Give permissions
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
public fun getLastKnownLocation(context: Context) {
val locationManager: LocationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val providers: List<String> = locationManager.getProviders(true)
var location: Location? = null
for (i in providers.size - 1 downTo 0) {
location= locationManager.getLastKnownLocation(providers[i])
if (location != null)
break
}
val gps = DoubleArray(2)
if (location != null) {
gps[0] = location.getLatitude()
gps[1] = location.getLongitude()
Log.e("gpsLat",gps[0].toString())
Log.e("gpsLong",gps[1].toString())
}
}
I would like to help someone who is trying to get location from scratch.
Here is the reference: Kotlin Get Current Location
Code will first check whether location is on or off in device and then will fetch latitude and longitudes and will update it constantly.
In build.gradle(Module:app) file put this
compile 'com.google.android.gms:play-services:11.8.0'
activity_main.xml code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Latitude:"
android:textSize="18sp" />
<TextView
android:id="#+id/latitude_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/latitude"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#+id/latitude"
android:textSize="16sp" />
<TextView
android:id="#+id/longitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Longitude:"
android:layout_marginTop="24dp"
android:textSize="18sp" />
<TextView
android:id="#+id/longitude_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/longitude"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#+id/longitude"
android:textSize="16sp"/>
</RelativeLayout>
MainActivity.kt
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import android.widget.Toast
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.model.LatLng
class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
private var mLatitudeTextView: TextView? = null
private var mLongitudeTextView: TextView? = null
private var mGoogleApiClient: GoogleApiClient? = null
private var mLocation: Location? = null
private var mLocationManager: LocationManager? = null
private var mLocationRequest: LocationRequest? = null
private val listener: com.google.android.gms.location.LocationListener? = null
private val UPDATE_INTERVAL = (2 * 1000).toLong() /* 10 secs */
private val FASTEST_INTERVAL: Long = 2000 /* 2 sec */
private var locationManager: LocationManager? = null
private val isLocationEnabled: Boolean
get() {
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mLatitudeTextView = findViewById(R.id.latitude_textview) as TextView
mLongitudeTextView = findViewById(R.id.longitude_textview) as TextView
mGoogleApiClient = GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build()
mLocationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
Log.d("gggg","uooo");
checkLocation() //check whether location service is enable or not in your phone
}
#SuppressLint("MissingPermission")
override fun onConnected(p0: 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) {
// mLatitudeTextView.setText(String.valueOf(mLocation.getLatitude()));
//mLongitudeTextView.setText(String.valueOf(mLocation.getLongitude()));
} else {
Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show()
}
}
override fun onConnectionSuspended(i: Int) {
Log.i(TAG, "Connection Suspended")
mGoogleApiClient!!.connect()
}
override fun onConnectionFailed(connectionResult: ConnectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode())
}
override fun onStart() {
super.onStart()
if (mGoogleApiClient != null) {
mGoogleApiClient!!.connect()
}
}
override fun onStop() {
super.onStop()
if (mGoogleApiClient!!.isConnected()) {
mGoogleApiClient!!.disconnect()
}
}
#SuppressLint("MissingPermission")
protected fun 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 fun onLocationChanged(location: Location) {
val msg = "Updated Location: " +
java.lang.Double.toString(location.latitude) + "," +
java.lang.Double.toString(location.longitude)
mLatitudeTextView!!.text = location.latitude.toString()
mLongitudeTextView!!.text = location.longitude.toString()
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
// You can now create a LatLng Object for use with maps
val latLng = LatLng(location.latitude, location.longitude)
}
private fun checkLocation(): Boolean {
if (!isLocationEnabled)
showAlert()
return isLocationEnabled
}
private fun showAlert() {
val dialog = AlertDialog.Builder(this)
dialog.setTitle("Enable Location")
.setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " + "use this app")
.setPositiveButton("Location Settings") { paramDialogInterface, paramInt ->
val myIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(myIntent)
}
.setNegativeButton("Cancel") { paramDialogInterface, paramInt -> }
dialog.show()
}
companion object {
private val TAG = "MainActivity"
}
}
gradle(Module: appname.app)
buildFeatures{
viewBinding true
} // for databinding
dependencies{
implementation 'com.google.android.gms:play-services-location:18.0.0'
}
manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
activity:
class Updateposition : AppCompatActivity() {
private lateinit var bind: ActivityUpdatepositionBinding
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
//private lateinit var lat: String // :Double
//private lateinit var long: String // ||.toDouble
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bind = ActivityUpdatepositionBinding.inflate(layoutInflater)
setContentView(bind.root)
//supportActionBar!!.hide()
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
try {
getActualLocation()
//getActualLocation()
//getActualLocation()
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
private fun getActualLocation() {
val task = fusedLocationProviderClient.lastLocation
if (ActivityCompat
.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat
.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 101)
return
}
task.addOnSuccessListener {
if (it != null){
bind.tvLatitude.text = "${it.latitude}" // it.longitude is a Double
bind.tvLongitude.text = "${it.longitude}" // tvLongitude is a TextView
}
}
}// one curly brace could be missing (or not)
run it then close your app then run again and voila!

Categories

Resources