<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Olubunmi Alegbeleye</title>
    <description>The latest articles on DEV Community by Olubunmi Alegbeleye (@olubunmialegbeleye).</description>
    <link>https://dev.to/olubunmialegbeleye</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F900574%2F9b392795-e10c-47b4-bc7c-8f697570338e.png</url>
      <title>DEV Community: Olubunmi Alegbeleye</title>
      <link>https://dev.to/olubunmialegbeleye</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olubunmialegbeleye"/>
    <language>en</language>
    <item>
      <title>Location Services- the Android 14 (maybe 15 too) way</title>
      <dc:creator>Olubunmi Alegbeleye</dc:creator>
      <pubDate>Tue, 16 Jul 2024 13:01:38 +0000</pubDate>
      <link>https://dev.to/olubunmialegbeleye/location-services-the-android-14-maybe-15-too-way-4171</link>
      <guid>https://dev.to/olubunmialegbeleye/location-services-the-android-14-maybe-15-too-way-4171</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Location awareness is becoming an essential part of many successful mobile applications. Whether you're building a fitness tracker, a navigation app, a ride-sharing app, a weather app, an augmented reality experience or a service that connects users based on proximity, incorporating location functionality can significantly enhance your app's value and user experience. &lt;/p&gt;

&lt;p&gt;This article helps you leverage the Location API in Android, providing a step-by-step approach to accessing the user's location, handling permissions, and setting up real-time location updates. By the end of this tutorial, you'll be well-equipped to integrate location-based features seamlessly into your Android projects. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up your project to use the Location API
&lt;/h2&gt;

&lt;p&gt;If you don't already have a project set up, follow the following steps:&lt;/p&gt;

&lt;p&gt;Open Android Studio. &lt;/p&gt;

&lt;p&gt;Go to &lt;strong&gt;File&lt;/strong&gt; &amp;gt; &lt;strong&gt;New&lt;/strong&gt; &amp;gt; &lt;strong&gt;New Project&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Select  &lt;strong&gt;Basic Views Activity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enter a name for your app&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Finish&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;app/build.gradle&lt;/code&gt; file and add the following dependency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
  //Location
  implementation 'com.google.android.gms:play-services-location:20.0.0'
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use the Gradle Kotlin DSL, add the following to the &lt;code&gt;libs.versions.toml&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[versions]
...
playlocation = "21.3.0"

[libraries]
...
play-location = { group = "com.google.android.gms", name = "play-services-location", version.ref = "playlocation"}

[plugins]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the &lt;code&gt;app/build.gradle.kts&lt;/code&gt; file, add this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
    ...
    implementation(libs.play.location)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click on &lt;strong&gt;Sync Project with Gradle Files&lt;/strong&gt; so that the just added dependency is available for use in your code.&lt;/p&gt;

&lt;p&gt;Add the following permissions to your AndroidManifest file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;manifest ...&amp;gt;
    &amp;lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&amp;gt;
    &amp;lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&amp;gt;
...
&amp;lt;/manifest&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ACCESS_FINE_LOCATION&lt;/strong&gt;: Grants access to the device's most precise location data (GPS, Wi-Fi, cell tower triangulation).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ACCESS_COARSE_LOCATION&lt;/strong&gt;: Provides a less accurate estimate using cell tower and Wi-Fi data (suitable for scenarios where exact coordinates aren't crucial).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Checking If your App has permission
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Activity.checkSelfPermission()&lt;/code&gt; checks if you have been granted a particular permission. To check if you have the &lt;code&gt;Manifest.permission.ACCESS_FINE_LOCATION&lt;/code&gt; permission, you would do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's use that to build a function that checks for the two permissions we need.&lt;/p&gt;

&lt;p&gt;Add the following to the activity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;(Code snippets are presented first in Kotlin and then in Java)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private fun isLocationPermissionGranted(activity: Activity): Boolean {
    return ActivityCompat.checkSelfPermission(
        activity,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED ||
            ActivityCompat.checkSelfPermission(
                activity,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private boolean isLocationPermissionGranted(Activity activity) {
    return ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
            ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function checks if your app has the permission to access the device's coarse or fine location.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requesting Permission at runtime
&lt;/h2&gt;

&lt;p&gt;In the activity where location is needed, you must request permission at runtime. We will use an &lt;code&gt;ActivityResultLauncher&lt;/code&gt; to request permission and listen for the response to our request. To indicate the kind of request, we have two options.  &lt;code&gt;ActivityResultContracts.RequestMultiplePermissions()&lt;/code&gt; or &lt;code&gt;ActivityResultContracts.RequestPermission()&lt;/code&gt;. We will use the former because we have two permissions to request.&lt;/p&gt;

&lt;p&gt;The next function requests for the needed permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private fun requestLocationPermission(callback: (Boolean) -&amp;gt; Unit) {
    val locationPermissionRequest = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions -&amp;gt;
        val fineLocationGranted: Boolean =
            permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false)
        val coarseLocationGranted: Boolean =
            permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false)

        if (fineLocationGranted || coarseLocationGranted) {
            callback(true) //permission granted
        } else {
            callback(false) //permission denied
        }

    }

    locationPermissionRequest.launch(
        arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private void requestLocationPermission(CallbackListener&amp;lt;Boolean&amp;gt; callbackListener) {

    ActivityResultLauncher&amp;lt;String[]&amp;gt; locationPermissionRequest = registerForActivityResult(
            new ActivityResultContracts.RequestMultiplePermissions(),
            permissions -&amp;gt; {
                Boolean fineLocationGranted = permissions.getOrDefault(android.Manifest.permission.ACCESS_FINE_LOCATION, false);
                Boolean coarseLocationGranted = permissions.getOrDefault(android.Manifest.permission.ACCESS_COARSE_LOCATION, false);
                if (
                        fineLocationGranted != null &amp;amp;&amp;amp; fineLocationGranted ||
                                coarseLocationGranted != null &amp;amp;&amp;amp; coarseLocationGranted
                ) {
                    // Permission granted
                    callbackListener.onCallback(true);
                } else {
                    // No location access granted.
                    callbackListener.onCallback(false);
                }
            });

    locationPermissionRequest.launch(new String[]{
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
    });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result, &lt;code&gt;permissions&lt;/code&gt;, is a &lt;code&gt;Map&lt;/code&gt; containing the permissions requested and whether they were granted. We look at the map for the two permissions requested. If either of them were granted, we're good. Else, we cannot use the Location API. You may present the user with a warning to let them know that some features may be unavailable or may not function properly since they have not granted the app the permission to access their device location.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check Phone's Location Settings
&lt;/h2&gt;

&lt;p&gt;Let's say the user granted the permission to access the device's location, we also need to check if the device's settings satisfy our requirements. For example, the device's location may be off. In this case, we cannot access the location.&lt;/p&gt;

&lt;p&gt;First, we build a location request. This is our way of specifying our requirements.&lt;/p&gt;

&lt;p&gt;Add the following field to your Activity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5000)
    .build()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private final LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5000)
        .build();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;SettingsClient.checkLocationSettings()&lt;/code&gt; to check if our requirement is met. If the requirement is met, we can proceed to the next step. If it isn't met, we need to ask the user to update their setting.&lt;/p&gt;

&lt;p&gt;For that, we need an &lt;code&gt;ActivityResultLauncher&lt;/code&gt; to launch the request and listen for the user's action.&lt;/p&gt;

&lt;p&gt;Add this field to your Activity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private val locationSettingsResult =
    registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -&amp;gt;
        when (result.resultCode) {
            Activity.RESULT_OK -&amp;gt; {
                //User has updated the device's setting
            }

            Activity.RESULT_CANCELED -&amp;gt; {
                //Warn user that location is required for some features
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private ActivityResultLauncher&amp;lt;IntentSenderRequest&amp;gt; locationSettingsResult;

public void onCreate(@Nullable Bundle savedInstanceState) {
    locationSettingsResult = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), result -&amp;gt; {
            if (result.getResultCode() == Activity.RESULT_OK) {
                //User has updated the device's setting
            } else {
                //Warn user that location is required for some features
            }
        });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;ActivityResultContracts&lt;/code&gt; must be registered before the Activity starts, or the app will crash.&lt;/p&gt;

&lt;p&gt;Putting it all together we have this function to check the device's location setting and ask the user to update their location settings if there is a need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private fun checkPhoneLocationSettings(
    activity: Activity,
    locationSettingsResult: ActivityResultLauncher&amp;lt;IntentSenderRequest&amp;gt;,
    callback: (Boolean) -&amp;gt; Unit
) {
    val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
    val client = LocationServices.getSettingsClient(activity)
    val task = client.checkLocationSettings(builder.build())

    task.addOnSuccessListener { callback(true) }

    task.addOnFailureListener { exception -&amp;gt;
        if (exception is ResolvableApiException) {
            try {
                locationSettingsResult.launch(
                    IntentSenderRequest.Builder(exception.resolution).build()
                )
            } catch (sendEx: IntentSender.SendIntentException) {
                // Ignore the error.
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private void checkPhoneLocationSettings(
        Activity activity,
        ActivityResultLauncher&amp;lt;IntentSenderRequest&amp;gt; locationSettingsResult,
        CallbackListener&amp;lt;Boolean&amp;gt; callbackListener) {

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
            .addLocationRequest(locationRequest);
    SettingsClient client = LocationServices.getSettingsClient(activity);

    Task&amp;lt;LocationSettingsResponse&amp;gt; task = client.checkLocationSettings(builder.build());

    task.addOnSuccessListener(activity, locationSettingsResponse -&amp;gt; {
        //Location settings are fine. You can start listening for location
        callbackListener.onCallback(true);
    });

    task.addOnFailureListener(activity, e -&amp;gt; {
        if (e instanceof ResolvableApiException) {
            locationSettingsResult.launch(new IntentSenderRequest.Builder(((ResolvableApiException) e).getResolution()).build());
        }
    });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we have what we need to check if we have location permission. If we don't we can request the permissions. After which we can check if the settings meet our location requirements. Let's package all of that into a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private fun setUpLocationComponentsAndGetLocation(activity: Activity) {
    if (isLocationPermissionGranted(activity)) {
        checkPhoneLocationSettings(activity) { isLocationSettingsOk -&amp;gt;
            if (isLocationSettingsOk) {
                //You can get last known location or request location update here because you have permission
                //and the device settings meet your requirement.
            } else {
                //warn user
            }
        }
    } else {
        requestLocationPermission { permissionGranted -&amp;gt;
            if (permissionGranted) {
                //simply a recursive call
                setUpLocationComponentsAndGetLocation(activity)
            } else {
                //warn user
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private void setUpLocationComponentsAndGetLocation(Activity activity) {
        if (isLocationPermissionGranted(activity)) {
        checkPhoneLocationSettings(activity, locationSettingsResult, isLocationSettingsOk -&amp;gt; {
            if (isLocationSettingsOk) {
                //You can get last known location or request location update here because you have permission
                //and the device settings meet your requirement.
            } else {
                //You may decide to warn users that some functions may not be available without permission

            }
        });
    } else {
        requestLocationPermission(permissionGranted -&amp;gt; {
            if (permissionGranted) {
                //simply a recursive call
                setUpLocationComponentsAndGetLocation(activity);
            } else {
                //Warn user
            }
        });
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accessing Location
&lt;/h2&gt;

&lt;p&gt;At this point, we can now access the device's location. &lt;code&gt;FusedLocationProviderClient&lt;/code&gt;  is the main entry point for interacting with the Fused Location Provider - the Location API by Google for accessing user location. To begin, add this field to your Activity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private val mFusedLocationProviderClient: FusedLocationProviderClient by lazy {
    LocationServices.getFusedLocationProviderClient(this)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private FusedLocationProviderClient fusedLocationProviderClient;
@Override
    protected void onStart() {
        super.onStart();
        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two methods of concern to us in the FusedLocationProviderClient class:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FusedLocationProviderClient.getLastLocation()&lt;/code&gt; retrieves the last known location while &lt;code&gt;FusedLocationProviderClient.requestLocationUpdates()&lt;/code&gt; listens for Location updates.&lt;/p&gt;

&lt;p&gt;For the former, think of Weather apps that get your current city and display the weather in that area. For the latter, think of Bolt or Uber which needs to get updates on the driver and rider's location.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving the last known location
&lt;/h2&gt;

&lt;p&gt;To retrieve the last known location of the device,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SuppressLint("MissingPermission")
private fun getLastLocation() {
    mFusedLocationProviderClient.lastLocation.addOnSuccessListener { location -&amp;gt;
        if (location != null) {
            // Logic to handle location object
            Log.d("Location", "Long" + location.longitude)
            Log.d("Location", "Lat" + location.latitude)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SuppressLint("MissingPermission")
private void getLastLocation() {
    fusedLocationProviderClient.getLastLocation().addOnSuccessListener(location -&amp;gt; {
        // Got last known location. In some rare situations this can be null.
        if (location != null) {
            // Logic to handle location object
            Log.d("Location", "Long" + location.getLongitude());
            Log.d("Location", "Lat" + location.getLatitude());
        }
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that you need to check for null because the last location may be null at some point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Location Updates for Real-time tracking
&lt;/h2&gt;

&lt;p&gt;This requires some more work compared to retrieving the last known location because we need to set up a callback and manage lifecycle.&lt;/p&gt;

&lt;p&gt;For the callback, add this field to your Activity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private val locationCallBack = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        super.onLocationResult(locationResult)
        Log.d("Location", "Long" + locationResult.lastLocation?.longitude)
        Log.d("Location", "Lat" + locationResult.lastLocation?.latitude)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private final LocationCallback locationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(@NonNull LocationResult locationResult) {
        super.onLocationResult(locationResult);
        if (locationResult.getLastLocation() != null) {
            Log.d("Location", "Long: " + locationResult.getLastLocation().getLongitude());
            Log.d("Location", "Lat: " + locationResult.getLastLocation().getLatitude());
        }
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember we created a &lt;code&gt;LocationRequest&lt;/code&gt; object when checking if the device setting meets our requirement. Well, we need the same object now.&lt;/p&gt;

&lt;p&gt;Create this function in your Activity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SuppressLint("MissingPermission")
private fun requestLocationUpdate(activity: Activity) {
    if (isLocationPermissionGranted(activity)) {
        mFusedLocationProviderClient.requestLocationUpdates(
            locationRequest,
            locationCallBack,
            Looper.getMainLooper()
        )
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SuppressLint("MissingPermission")
private void requestLocationUpdate(Activity activity) {
    if (isLocationPermissionGranted(activity)) {
        fusedLocationProviderClient.requestLocationUpdates(
                locationRequest,
                locationCallback,
                Looper.getMainLooper()
        );
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting it all up
&lt;/h2&gt;

&lt;p&gt;Now that we have the function to Get the last known location and request location updates, it is time to update our &lt;code&gt;setUpLocationComponentsAndGetLocation()&lt;/code&gt;&lt;br&gt;
 from before. Add the new lines to the &lt;code&gt;setUpLocationComponentsAndGetLocation()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private fun setUpLocationComponentsAndGetLocation(activity: Activity) {
    if (isLocationPermissionGranted(activity)) {
        checkPhoneLocationSettings(activity) { isLocationSettingsOk -&amp;gt;
            if (isLocationSettingsOk) {
                getLastLocation() //Add only this line to get the last location
                requestLocationUpdate(activity) //Add only this line, to request location updates
            } else {
                //warn user
            }
        }
    } else {
        requestLocationPermission { permissionGranted -&amp;gt;
            if (permissionGranted) {
                //simply a recursive call
                setUpLocationComponentsAndGetLocation(activity)
            } else {
                //warn user
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private void setUpLocationComponentsAndGetLocation(Activity activity) {
        if (isLocationPermissionGranted(activity)) {
        checkPhoneLocationSettings(activity, locationSettingsResult, isLocationSettingsOk -&amp;gt; {
            if (isLocationSettingsOk) {
                getLastLocation(); //Add only this line to get the last location
                requestLocationUpdate(activity); //Add only this line, to request location updates
            } else {
                //You may decide to warn users that some functions may not be available without permission

            }
        });
    } else {
        requestLocationPermission(permissionGranted -&amp;gt; {
            if (permissionGranted) {
                //simply a recursive call
                setUpLocationComponentsAndGetLocation(activity);
            } else {
                //Warn user
            }
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get location or request location update, all you need do at this point is to call the &lt;code&gt;setUpLocationComponentsAndGetLocation()&lt;/code&gt; from the entry point of the Activity that needs location data. Usually, this is the &lt;code&gt;onStart()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override fun onStart() {
    super.onStart()
    setUpLocationComponentsAndGetLocation(this)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
protected void onStart() {
    super.onStart();
    setUpLocationComponentsAndGetLocation(this);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cleaning up after yourself
&lt;/h2&gt;

&lt;p&gt;One final and important thing. When you no longer require the location updates, you need to unsubscribe. This most likely happens when the user navigates away from the Activity that requires the location update. It is a best practice to stop location updates by removing the location callback. This way, you can avoid unnecessarily draining the device battery.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override fun onStop() {
    mFusedLocationProviderClient.removeLocationUpdates(locationCallBack)
    super.onStop()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
protected void onStop() {
    fusedLocationProviderClient.removeLocationUpdates(locationCallback);
    super.onStop();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Integrating location functionality into your Android applications can significantly enhance user experience and provide valuable features for a wide range of applications. By following this step-by-step guide, you now know how to access the user's location, handle permissions, set up real-time location updates, and ensure your app meets the necessary location settings requirements. Implementing these features will allow you to create more dynamic and contextually aware applications. &lt;/p&gt;

&lt;p&gt;This guide helped you leverage the Android Location API effectively in your mobile applications. It discussed the process of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrating the Location API dependency within your project.&lt;/li&gt;
&lt;li&gt;Requesting and handling location permissions at runtime.&lt;/li&gt;
&lt;li&gt;Verifying that the device's location settings meet your app's requirements.&lt;/li&gt;
&lt;li&gt;Retrieving the user's last known location.&lt;/li&gt;
&lt;li&gt;Setting up real-time location updates.&lt;/li&gt;
&lt;li&gt;Stopping location updates to optimize battery usage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following the steps in this article, you can add location-based functionalities to enhance your Android apps, create more dynamic and contextually aware applications and deliver a superior user experience.&lt;/p&gt;

&lt;p&gt;For a complete example, you can refer to the repository at &lt;a href="https://github.com/olubunmialegbeleye/Location" rel="noopener noreferrer"&gt;https://github.com/olubunmialegbeleye/Location&lt;/a&gt;. Happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Validating phone numbers using Google's libphonenumber library</title>
      <dc:creator>Olubunmi Alegbeleye</dc:creator>
      <pubDate>Wed, 01 Feb 2023 13:36:24 +0000</pubDate>
      <link>https://dev.to/olubunmialegbeleye/validating-phone-numbers-using-googles-libphonenumber-library-14ne</link>
      <guid>https://dev.to/olubunmialegbeleye/validating-phone-numbers-using-googles-libphonenumber-library-14ne</guid>
      <description>&lt;h2&gt;
  
  
  What is libphonenumber?
&lt;/h2&gt;

&lt;p&gt;Libphonenumber is Google’s library for parsing, formatting, and validating international phone numbers in Java, C++, and JavaScript. That sounds interesting. So, I can use this library to validate the phone numbers of any country.&lt;/p&gt;

&lt;p&gt;Libphonenumber is a powerful library — it is a Swiss army knife. We will focus mostly on validating phone numbers with this library.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://github.com/google/libphonenumber"&gt;Github repo and documentation&lt;/a&gt; for the library here.&lt;/p&gt;

&lt;p&gt;If you are collecting user phone numbers in your application and need to validate that they are correct, then read on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing the library into an Android Project
&lt;/h2&gt;

&lt;p&gt;To add libphonenumber to your Android Studio Project, add these to your project-level build.gradle file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Enable Maven Repository in your project if it has not yet been done:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repositories {
  mavenCentral()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add this line to your app-level build.gradle file to compile the dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
    ...
    implementation 'com.googlecode.libphonenumber:libphonenumber:8.2.0'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rebuild your project so that Gradle can fetch the dependencies. After you have successfully built it, the library will be available for you to use in your app module.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Validating Nigerian Phone Numbers
&lt;/h2&gt;

&lt;p&gt;Now that you have imported the library, let’s use it to validate Nigerian phone numbers.&lt;/p&gt;

&lt;p&gt;Import the following in your java/android class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.google.i18n.phonenumbers.PhoneNumberUtil
import com.google.i18n.phonenumbers.Phonenumber
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an instance of the PhoneNumberUtil class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
private val phoneNumberUtil = PhoneNumberUtil.getInstance()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the utility class for formatting, parsing, and validating international phone numbers. In case you like to read Javadocs, &lt;a href="https://javadoc.io/doc/com.googlecode.libphonenumber/libphonenumber/latest/com/google/i18n/phonenumbers/PhoneNumberUtil.html"&gt;here is the link to the class’s Javadoc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I know, just like me, you don’t, just follow along and I will show you how this works. &lt;em&gt;“I gat you”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This util class has a method &lt;code&gt;isValidNumber()&lt;/code&gt; that returns true if the phone number matches a valid pattern and false otherwise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
public boolean isValidNumber(Phonenumber.PhoneNumber number)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
fun isValidNumber(number: Phonenumber.PhoneNumber): Boolean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did I just read pattern and matching? Yes, you read right. Maybe that brings the dreaded regular expression to mind. Luckily for you and me, this util class and its functions replace all of that jargon. So, out with the regex.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The &lt;code&gt;PhoneNumberUtil&lt;/code&gt; class also has a method &lt;code&gt;isValidForRegion()&lt;/code&gt; that accepts region code in addition to &lt;code&gt;isValidNumber()&lt;/code&gt;’s PhoneNumber parameter.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But where does this &lt;code&gt;PhoneNumber.Number number&lt;/code&gt; parameter come from? The PhoneNumber class represents/stores a phone number. Javadoc people, &lt;a href="https://javadoc.io/static/com.googlecode.libphonenumber/libphonenumber/8.13.5/com/google/i18n/phonenumbers/Phonenumber.PhoneNumber.html"&gt;here you go again&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is how you create an instance of the PhoneNumber class — a PhoneNumber object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
Phonenumber.PhoneNumber rawPhoneNumber = new Phonenumber.PhoneNumber();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
val rawPhoneNumber = Phonenumber.PhoneNumber()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, pass the country code and the national number you got from the user into the object you just created. Usually, you get these from two text fields or a drop-down menu and a text field in your user interface.&lt;/p&gt;

&lt;p&gt;You have to parse the country code into an integer and the phone number into a long.&lt;/p&gt;

&lt;p&gt;For Nigeria, the country code is “+234” or 234 in integer&lt;/p&gt;

&lt;p&gt;and the national number is the user’s phone number in a format that can be dialled locally from Nigeria. That is the format: 080X XXX XXXX or 80X XXX XXXX.&lt;/p&gt;

&lt;p&gt;At this point, all you need to do is set the two fields in the Phonenumber object you created, thus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
Phonenumber.PhoneNumber rawPhoneNumber = new Phonenumber.PhoneNumber();
rawPhoneNumber.setCountryCode(123);
rawPhoneNumber.setNationalNumber(123L);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
val rawPhoneNumber = Phonenumber.PhoneNumber()
rawPhoneNumber.countryCode = countryCodeEditText.text.toString().toInt()
rawPhoneNumber.nationalNumber = phoneEditText.text.toString().toLong()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To validate, pass this phone number object to the &lt;code&gt;isValidNumber()&lt;/code&gt; function you came across earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
Phonenumber.PhoneNumber rawPhoneNumber = new Phonenumber.PhoneNumber();
rawPhoneNumber.setCountryCode(123);
rawPhoneNumber.setNationalNumber(123L);
boolean isValidNumber = phoneNumberUtil.isValidNumber(rawPhoneNumber);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
val rawPhoneNumber = Phonenumber.PhoneNumber()
rawPhoneNumber.countryCode = countryCodeEditText.text.toString().toInt()
rawPhoneNumber.nationalNumber = phoneEditText.text.toString().toLong()
val isValid = phoneNumberUtil.isValidNumber(rawPhoneNumber)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To save user details on your server, you can pass both components of the phone number you have collected and validated as a JSON object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "userPhoneNumber" : {
    "country_code": 234,
    "national_number": 8012345678
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you may want to send it to your server in the international form. For example +23490X XXX XXXX for Nigeria. There is information on how to get the validated phone number in the international format in the sidebar.&lt;/p&gt;

&lt;p&gt;In this short article, we saw in action a powerful library that replaces all those ugly regular expressions when validating phone numbers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sidebar: Parsing and Formatting phone numbers with libphonenumber
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Formatting Phone Numbers
&lt;/h3&gt;

&lt;p&gt;You may need to format the validated phone number in a different format. That is where the PhoneNumberUtil’s formatting ability comes in. Just do this. In this example, we format the phone number as an E.164 number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
String internationalFormat = phoneNumberUtil.format(rawPhoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
internationalFormat = phoneNumberUtil.format(rawPhoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t be confused with that second parameter. They are constants in the util class that represents different phone number formats: E164, INTERNATIONAL, NATIONAL, and RFC3966.&lt;/p&gt;

&lt;p&gt;So, you’re just telling PhoneNumberUtil in what format you want your output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parsing Phone Numbers
&lt;/h3&gt;

&lt;p&gt;Let’s briefly learn about parsing phone numbers with PhoneNumberUtil.&lt;/p&gt;

&lt;p&gt;If you have your phone number in any format (E164, national, international, etc), even if the phone number is embedded in a string, just invoke the parse function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Java
Phonenumber.PhoneNumber parsedPhoneNumber = phoneNumberUtil.parse(CharSequence numberToParse, String regionCode);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Kotlin
val parsedPhoneNumber = PhoneNumberUtil.parse(numberToParse: CharSequence, regionCode: String)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The region code identifies what region the number is expected to be from. That’s NG for Nigeria. And &lt;em&gt;kaboom!&lt;/em&gt;, you have phoneNumber in &lt;code&gt;PhonenNumber.PhoneNumber&lt;/code&gt; form.&lt;/p&gt;

&lt;p&gt;The country code and the national number have been parsed into individual fields like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "country_code": 234,
  "national_number": 8012345678
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a warning!!!&lt;/p&gt;

&lt;p&gt;If you pass a string that cannot be parsed into &lt;code&gt;PhoneNumberUtil.parse()&lt;/code&gt;, say because it doesn’t contain a valid phone number, a &lt;code&gt;NumberParseException&lt;/code&gt; is thrown. Usually, we surround things like this in try-catch blocks, but the ball (or the exception in this case) is in your court.&lt;/p&gt;

</description>
      <category>android</category>
      <category>java</category>
      <category>kotlin</category>
    </item>
  </channel>
</rss>
