In this tutorial, we’re building a car location tracking app like Careem and Uber. Although we’re not developing complete apps like Uber and Careem. But we’ll see how to online a driver and show the online driver in the passenger app and update the driver whenever its current location changed.

For online and offline the driver we’re going to use the Firebase Real-time Database. The driver simply sends its current location to the firebase and passenger see the driver on the Google Map.

Below is the demo of applications which we gonna make in this article.


  1. You’ve to have a Google Map API key for showing the Map. See this link for getting the API key.
  2. Need a Firebase project for the real-time database. Click to this link for creating a Firebase project.

Now we’ve Google Map API key and a Firebase project let’s dive into coding and start building our mobile applications.

Android App Coding:

Like I said earlier, there are two apps one for driver and one for the passenger. So, we’re gonna start making with the driver app.


First, add the below dependencies to your app level build.gradle file.

implementation ''
implementation ''
implementation ''

After adding the dependencies you need to sync or build your project. Later the successful build adds the Internet and Location permission to Android. Manifest file.

<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" />

Now, to show the Google Maps in the app we need to add the meta tags in Android. Manifest file.

    android:value="@integer/google_play_services_version" />

    android:value="@string/map_api_key" />   // Change it with your Google Maps API key.

All the prep work are done for showing the Google Maps and for reading the user current Location. Now, we need to add the google-services.json file. In this tutorial, I’m not gonna show you how to create a firebase project, register your Android app to that firebase project, and add the google-services.json file in Android app. There’s a link for a video to add the google-services.json file in Android app.

So, without further ado let’s dive into coding. Below is the UI of the driver app that we’re gonna make.

Driver Tracker App Main Screen

You see the UI is very basic, we’ve one SwitchCompat for online and offline the driver and below is the Google Map itself. Now let’s see the code of the above UI. Below is the activity_main.xml file.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=""


            android:textSize="22sp" />

            android:theme="@style/SCBSwitch" />


        tools:context="" />



class MainActivity : AppCompatActivity() {

    companion object {
        private const val MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 2200

    private lateinit var googleMap: GoogleMap
    private lateinit var locationProviderClient: FusedLocationProviderClient
    private lateinit var locationRequest: LocationRequest
    private lateinit var locationCallback: LocationCallback
    private var locationFlag = true
    private var driverOnlineFlag = false
    private var currentPositionMarker: Marker? = null
    private val googleMapHelper = GoogleMapHelper()
    private val firebaseHelper = FirebaseHelper("0000")
    private val markerAnimationHelper = MarkerAnimationHelper()
    private val uiHelper = UiHelper()

    override fun onCreate(savedInstanceState: Bundle?) {
        val mapFragment: SupportMapFragment = supportFragmentManager.findFragmentById( as SupportMapFragment
        mapFragment.getMapAsync { googleMap = it }
        locationProviderClient = LocationServices.getFusedLocationProviderClient(this)
        locationRequest = uiHelper.getLocationRequest()
        if (!uiHelper.isPlayServicesAvailable(this)) {
            Toast.makeText(this, "Play Services did not installed!", Toast.LENGTH_SHORT).show()
        } else requestLocationUpdate()
        val driverStatusTextView = findViewById<TextView>(
        findViewById<SwitchCompat>( { _, b ->
            driverOnlineFlag = b
            if (driverOnlineFlag) driverStatusTextView.text = resources.getString(R.string.online_driver)
            else {
                driverStatusTextView.text = resources.getString(R.string.offline)

    private fun requestLocationUpdate() {
        if (!uiHelper.isHaveLocationPermission(this)) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION)
        if (uiHelper.isLocationProviderEnabled(this))
            uiHelper.showPositiveDialogWithListener(this, resources.getString(R.string.need_location), resources.getString(R.string.location_content), object : IPositiveNegativeListener {
                override fun onPositive() {
            }, "Turn On", false)
        locationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())

    private fun createLocationCallback() {
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {
                if (locationResult!!.lastLocation == null) return
                val latLng = LatLng(locationResult.lastLocation.latitude, locationResult.lastLocation.longitude)
                Log.e("Location", latLng.latitude.toString() + " , " + latLng.longitude)
                if (locationFlag) {
                    locationFlag = false
                if (driverOnlineFlag) firebaseHelper.updateDriver(Driver(lat = latLng.latitude, lng = latLng.longitude))

    private fun showOrAnimateMarker(latLng: LatLng) {
        if (currentPositionMarker == null)
            currentPositionMarker = googleMap.addMarker(googleMapHelper.getDriverMarkerOptions(latLng))
        else markerAnimationHelper.animateMarkerToGB(currentPositionMarker!!, latLng, LatLngInterpolator.Spherical())

    private fun animateCamera(latLng: LatLng) {
        val cameraUpdate = googleMapHelper.buildCameraUpdate(latLng)
        googleMap.animateCamera(cameraUpdate, 10, null)

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
            val value = grantResults[0]
            if (value == PERMISSION_DENIED) {
                Toast.makeText(this, "Location Permission denied", Toast.LENGTH_SHORT).show()
            } else if (value == PERMISSION_GRANTED) requestLocationUpdate()

In MainActivity there are a bunch of important points which I’m going to explain below.

  1.  createLocationCallback: We’re calling this function from the onCreate method of our MainActivity. In the LocationCallback abstract method, we’ll get the user current location, update the Driver info on Firebase Real-time database if the driver is online, and animate driver car Marker from the previous Location to a new one.
  2. requestLocationUpdates: Calling this function from the onCreate method of MainActivity if the user has installed GooglePlayServices in his/her mobile. In this method first, we request the Location permission from the user, then we check if the Location provider is enabled, and finally start the location updates.
  3. showOrAnimateMarker: In this method first we check if the driver car Marker is null then we simply add a new Marker to Google Maps else we animate the Marker.
  4. animteCamera: This method is called from createLocationCallback method only once because, we only want to animate the Google Maps to driver current location when he/she opens the app.
  5. onRequestPermissionsResult: Callback of the result of requesting location permission. This method invoked when the user performs an action on permission. Now in this method, if the user denies the permission then we simply show the toast else start the current location updates.


class UiHelper {

    fun isPlayServicesAvailable(context: Context): Boolean {
        val googleApiAvailability = GoogleApiAvailability.getInstance()
        val status = googleApiAvailability.isGooglePlayServicesAvailable(context)
        return ConnectionResult.SUCCESS == status

    fun isHaveLocationPermission(context: Context): Boolean {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED

    fun isLocationProviderEnabled(context: Context): Boolean {
        val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)

    fun showPositiveDialogWithListener(callingClassContext: Context, title: String, content: String, positiveNegativeListener: IPositiveNegativeListener, positiveText: String, cancelable: Boolean) {
        buildDialog(callingClassContext, title, content)
                .positiveColor(getColor(R.color.colorPrimary, callingClassContext))
                .onPositive { _, _ -> positiveNegativeListener.onPositive() }

    private fun buildDialog(callingClassContext: Context, title: String, content: String): MaterialDialog {
        return MaterialDialog.Builder(callingClassContext)

    private fun getColor(color: Int, context: Context): Int {
        return ContextCompat.getColor(context, color)

    fun getLocationRequest() : LocationRequest {
        val locationRequest = LocationRequest.create()
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        locationRequest.interval = 3000
        return locationRequest

The following explains UiHelper class methods.

  1. isPlayServicesAvailable: This method checks that if the user currently has Google Play Services installed or not.
  2. isHaveLocationPermission: Checks that if a user gives the Location permission or not.
  3. isLocationProviderEnabled: Checks if the Location provider enabled or not. If not then open the Settings activity and turn on the Location Provider.
  4. showPositiveDialogWithListener: Utility function to show the Dialog when the user has not enabled the location provider in mobile settings.


class GoogleMapHelper {

    companion object {
        private const val ZOOM_LEVEL = 18
        private const val TILT_LEVEL = 25

     * @param latLng in which position to Zoom the camera.
     * @return the [CameraUpdate] with Zoom and Tilt level added with the given position.

    fun buildCameraUpdate(latLng: LatLng): CameraUpdate {
        val cameraPosition = CameraPosition.Builder()
        return CameraUpdateFactory.newCameraPosition(cameraPosition)

     * @param position where to draw the []
     * @return the [MarkerOptions] with given properties added to it.

    fun getDriverMarkerOptions(position: LatLng): MarkerOptions {
        val options = getMarkerOptions(R.drawable.car_icon, position)
        return options

    private fun getMarkerOptions(resource: Int, position: LatLng): MarkerOptions {
        return MarkerOptions()


class MarkerAnimationHelper {

    fun animateMarkerToGB(marker: Marker, finalPosition: LatLng, latLngInterpolator: LatLngInterpolator) {
        val startPosition = marker.position
        val handler = Handler()
        val start = SystemClock.uptimeMillis()
        val interpolator = AccelerateDecelerateInterpolator()
        val durationInMs = 2000f : Runnable {
            var elapsed: Long = 0
            var t: Float = 0.toFloat()
            var v: Float = 0.toFloat()
            override fun run() {
                // Calculate progress using interpolator
                elapsed = SystemClock.uptimeMillis() - start
                t = elapsed / durationInMs
                v = interpolator.getInterpolation(t)
                marker.position = latLngInterpolator.interpolate(v, startPosition, finalPosition)
                // Repeat till progress is complete.
                if (t < 1) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16)

The above MarkerAnimationHelper class animate the driver car Marker from the previous location to user new Location.


interface LatLngInterpolator {

    fun interpolate(fraction: Float, a: LatLng, b: LatLng): LatLng

    class Spherical : LatLngInterpolator {

        override fun interpolate(fraction: Float, a: LatLng, b: LatLng): LatLng {
            val fromLat = toRadians(a.latitude)
            val fromLng = toRadians(a.longitude)
            val toLat = toRadians(b.latitude)
            val toLng = toRadians(b.longitude)
            val cosFromLat = cos(fromLat)
            val cosToLat = cos(toLat)

            // Computes Spherical interpolation coefficients.
            val angle = computeAngleBetween(fromLat, fromLng, toLat, toLng)
            val sinAngle = sin(angle)
            if (sinAngle < 1E-6) {
                return a
            val temp1 = sin((1 - fraction) * angle) / sinAngle
            val temp2 = sin(fraction * angle) / sinAngle

            // Converts from polar to vector and interpolate.
            val x = temp1 * cosFromLat * cos(fromLng) + temp2 * cosToLat * cos(toLng)
            val y = temp1 * cosFromLat * sin(fromLng) + temp2 * cosToLat * sin(toLng)
            val z = temp1 * sin(fromLat) + temp2 * sin(toLat)

            // Converts interpolated vector back to polar.
            val lat = atan2(z, sqrt(x * x + y * y))
            val lng = atan2(y, x)
            return LatLng(toDegrees(lat), toDegrees(lng))

        private fun computeAngleBetween(fromLat: Double, fromLng: Double, toLat: Double, toLng: Double): Double {
            val dLat = fromLat - toLat
            val dLng = fromLng - toLng
            return 2 * asin(sqrt(pow(sin(dLat / 2), 2.0) + cos(fromLat) * cos(toLat) * pow(sin(dLng / 2), 2.0)))

The LatLngInterpolator interface helps to animate the driver car Marker.


class FirebaseHelper constructor(driverId: String) {

    companion object {
        private const val ONLINE_DRIVERS = "online_drivers"

    private val onlineDriverDatabaseReference: DatabaseReference = FirebaseDatabase

    init {

    fun updateDriver(driver: Driver) {
        Log.e("Driver Info", " Updated")

    fun deleteDriver() {

Before going to start to explain FirebaseHelper, I want to show you Firebase Real-time Database Structure.

Firebase Realtime Database

The following explains about FirebaseHelper class.

  1. onlineDriverDatabaseReference: When creating a DatabaseReference, we’re adding two children one for online drivers node and another one for the Driver itself. We need to inform firebase real-time database in which node to update the Diver that’s why I’m setting driverId as a top node and below the is the complete Driver object. The driverId must be unique because it differs in whole online drivers node which specific driver node to update.
  2. updateDriver: Update the Driver new Location to firebase real-time database.
  3. deleteDriver: Removes the driver node from firebase real-time database.


data class Driver(val lat: Double, val lng: Double, val driverId: String = "0000")

You can change driverId with the user primary key any anything which is unique.

Alright, guys, this was all from DriverApp. I’m going to end this article here if you want to see the Passenger app see the next article. If you’ve any queries regarding this post please do comment below.

Download Complete Code

Thank you for being here and keep reading…

Next Part


I’m a mobile product devsigner (i.e. I consider myself as both a developer and a designer) and user experience/interface engineer. I’m an expert on the Android platform and have been recognized as it by the community.


  1. Mr Ahsen please help im stuck.
    shows error upon sync
    “File google-services.json is missing. The Google Services Plugin cannot function without it.
    Searched Location: “

    • Ahsen Saeed Reply

      Hey AGA,
      You need to first create a firebase project, then download the google-services.json file in app directory of your Android Project.

    • Ahsen Saeed Reply

      Hey Zareen,
      You don’t need to create firebase database structure. It’ll automatically created for you when you upload your driver data on firebase. You just need to create your java or kotlin class model then simply upload it to firebase.

  2. Anshu Verma Reply

    In Java version of the app, how can I add a user’s name in place of “0000”(driver id) if I am getting the user name from an eddittext .

    • Ahsen Saeed Reply

      Hey Anshu Verma,
      Simple rename the driverId field to name field and pass the edittext name in the constructor and finally upload the object to firebase database.

  3. How could I set the Google user as the Driver ID if I login via Google Sign-In?

    • Ahsen Saeed Reply

      Just pass the driverId in the Driver constructor when creating a driver object.

  4. Anshu Verma Reply

    There is a problem in both Java and kotlin version of the app, whenever I switch on location switch it sends location data to the database perfectly but when I tap the back button and reopen the app the switch is turned off, but the location data is still present in the database and now that data can’t be removed from the database until you uninstall the app from your device. Please tell me how can I fix this.

    • Ahsen Saeed Reply

      Hey Anshu,
      This happens becuase there’s only one Activity in our application. When you press the back button the application quits. So, we need to prevent our application to close down on back button. The following shows how to prevent the application closing.

      public void onBackPressed() {


      public boolean onKeyDown(int keyCode, KeyEvent event) {
      switch (keyCode) {
      case KeyEvent.KEYCODE_BACK:
      return true;
      return false;

      Now try to close down the application with swipe gesture you’ll see the driver info from firebase will remove.

    • Ahsen Saeed Reply

      I’m so sorry for late reply. Yes, I will upload code at the of Sunday night on GitHub.

      • Mr.Ahsen Saeed, I am not able to find the java version code, could you please give me the link, thank you.

      • Mr. Ahsen Saeed, I am not able to find java version, could you please give me the link, thank you.

          • vickey rajak Reply

            Mr. Ahsen Saeed, I got the driver app from the GitHub but I am not able to find java version of Passenger app, could you please give me the link, Thank you.

Write A Comment