Android Phones

Getting Current Location in Android using Kotlin

Jayant dhingra
Getting Current Location in Android using Kotlin
Current Location in Android using Kotlin

So in this tutorial, we’ll be learning about getting the user’s current location in Android using kotlin (latitude & longitude).

We will be using Fused Location Provider.

The fused location provider retrieves the device’s last known location. The fused location provider is one of the location APIs in Google Play services.

It manages the underlying location technology and provides a simple API so that you can specify requirements at a high level, like high accuracy or low power. 

STEP – 1

Add dependency in build.gradle file of you app.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //.....
    //.....

    implementation 'com.google.android.gms:play-services-location:17.4.3'
}

STEP – 2

Ask for Location permission from User. Since Location is a dangerous Permission for android so we need to ask the user to grant permission for it.

Android offers two location permissions:

  1. ACCESS_COARSE_LOCATION
  2. ACCESS_FINE_LOCATION.

The permission you choose determines the accuracy of the location returned by the API.

Add these two permission in you manifest file.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

STEP – 3

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, the user may not clearly understand about important permission of their device.

As we need the location information of the user so we’ll need to implement the permission request also in runtime.

Read More: How To Use Retrofit Tutorial in Kotlin

These will be in further Steps

PART – 1

checkPermissions()

This method will tell us whether or not the user grant us to access ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION.

private fun checkPermissions(): Boolean {
    if (
ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission 
 (this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
        return true
    }
    return false
}

PART – 2

onRequestPermissionsResult()

This method is called when a user Allow or Deny our requested permissions. So it will help us to move forward if the permissions are granted.

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    if (requestCode == PERMISSION_ID) {
        if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
            // Granted. Start getting the location information
        }
    }
}

PART – 3

isLocationEnabled()

This will check if the user has turned on location from the setting, Cause user may grant the app to user location but if the location setting is off then it’ll be of no use.

private fun isLocationEnabled(): Boolean {
    var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
        LocationManager.NETWORK_PROVIDER
    )
}

You may notice that while requesting for permission and in after the permission result, we used PERMISSION_ID, it’s a interger value which helps us to identify user’s action with which permission request. You can provide any unique value here.

STEP – 4

Now time to write the MainActivity.kt

package com.jayant.mylocation

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.LocationManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.ActivityCompat

class MainActivity : AppCompatActivity() {

    val PERMISSION_ID = 42
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    private fun isLocationEnabled(): Boolean {
        var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
            LocationManager.NETWORK_PROVIDER
        )
    }

    private fun checkPermissions(): Boolean {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
            return true
        }
        return false
    }

    private fun requestPermissions() {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
            PERMISSION_ID
        )
    }


    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        if (requestCode == PERMISSION_ID) {
            if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // Granted. Start getting the location information
            }
        }
    }
}

STEP – 6

Now we’ll use the actual Fused Location Provider API to get the user’s current position. For this, you should declare a variable first lateint var using mFusedLocationClient: FusedLocationClient

Then we’ll create a method named getLastLocation() which will use to API and return the last recorder location information of the device. Also this method will check first if our permission is granted or not and if the location setting is turned on.

@SuppressLint("MissingPermission")
private fun getLastLocation() {
    if (checkPermissions()) {
        if (isLocationEnabled()) {

            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()
                }
            }
        } else {
            Toast.makeText(this, "Turn on location", Toast.LENGTH_LONG).show()
            val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
            startActivity(intent)
        }
    } else {
        requestPermissions()
    }
}

As you can see first it’ll check if we have granted permissions or not using our created method checkPermission()  and if not, it’ll request for location permission. Then it’ll check if the location setting is turned on or off. If turned off, will open the location setting using intent to turn it on.

If every requirment is good then it’ll look for the last recorded location information and put the latitude and longitude values in our TextView using

latTextView.text = location.latitude.toString()
lonTextView.text =location.longitude.toString()

STEP – 7

FINAL Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">

    <TextView
            android:id="@+id/latTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Latitude: "/>

    <TextView
            android:id="@+id/lonTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Longitude: "/>

</LinearLayout>

STEP – 8 (optional)

But here’s a thing you must know, for some rare cases the location can be null like:

  • In some device, if you turn off the location and again turn on, the previous recorded location information will be cleared.
  • May the user never turned on location before using your App, this time previous location information will be null too.

To avoid these rare cases when the location == null, we called a new method requestNewLocation() which will record the location information in runtime.

@SuppressLint("MissingPermission")
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()
    )
}

This method will make a new location request with highest accuracy.

When an update receives it’ll call a callBack method named mLocationCallback.

private val mLocationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        var mLastLocation: Location = locationResult.lastLocation
        findViewById<TextView>(R.id.latTextView).text = mLastLocation.latitude.toString()
        findViewById<TextView>(R.id.lonTextView).text = mLastLocation.longitude.toString()
    }
}

So when we get the location update, we set the latitude and longitude values in our TextViews.

So finally we’ll call our getLastLocation() method in our onCreate() method and also when user grants the permission request.

Final MainActivity.kt

package com.jayant.mylocation

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 androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.provider.Settings
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.*

class MainActivity : AppCompatActivity() {

    val PERMISSION_ID = 42
    lateinit var mFusedLocationClient: FusedLocationProviderClient
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

        getLastLocation()
    }

    @SuppressLint("MissingPermission")
    private fun getLastLocation() {
        if (checkPermissions()) {
            if (isLocationEnabled()) {

                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()
                    }
                }
            } else {
                Toast.makeText(this, "Turn on location", Toast.LENGTH_LONG).show()
                val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
                startActivity(intent)
            }
        } else {
            requestPermissions()
        }
    }

    @SuppressLint("MissingPermission")
    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()
        )
    }

    private val mLocationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            var mLastLocation: Location = locationResult.lastLocation
            findViewById<TextView>(R.id.latTextView).text = mLastLocation.latitude.toString()
            findViewById<TextView>(R.id.lonTextView).text = mLastLocation.longitude.toString()
        }
    }

    private fun isLocationEnabled(): Boolean {
        var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
            LocationManager.NETWORK_PROVIDER
        )
    }

    private fun checkPermissions(): Boolean {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            return true
        }
        return false
    }

    private fun requestPermissions() {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
            PERMISSION_ID
        )
    }


    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        if (requestCode == PERMISSION_ID) {
            if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                getLastLocation()
            }
        }
    }
}

Thats all Folks !