android location updates fused client playe services

How to get user location in Android

Android Play Services SDK offers Location API that is used to get gps location. Location updates is one of the most crucial feature of Android apps. We have seen in one of the earlier post on how to use Places API to auto complete address.  In this post we will see how to automatically track user location and how to get user consent to get location updates programatically.

Setup Location API

The first step before using location api is to add permission in AndroidManifest.xml and Location dependency in build.gradle.

Add location dependency in app’s build.gradle file and sync the project.

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

Add uses-permission in AndroidManifest.xml file to request location.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.codeexa.locationsample">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Last Known Location

Location API can be requested to get the last known location of the user. The accuracy of the location is based on the permission set in the app. For instance ACCESS_FINE_LOCATION gives a better accuracy than ACCESS_COARSE_LOCATION but requires users consent to allow app permission.

Let’s see how to use Fused Location Client to get last location.

Create Fused Location Provider instance as shown in the code below.

    
    private FusedLocationProviderClient mLocationProviderClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);

        checkPermissionAndRequestLocation();
    }

To get the last known location call getLastLocation() method that returns a task that can be used to retrieve location data as shown in the code method below. Before we request location updates we need to check if we have the permission to request location. It is essential to ask user to grant permission if the app is targeting SDK  Marshmallow 23 or above or if the device running is Android (6.0) or above.

     private static final int RC_LOCATION_REQUEST = 1234;

     private void checkPermissionAndRequestLocation() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, RC_LOCATION_REQUEST );
        }else {
            mLocationProviderClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
                @Override
                public void onComplete(@NonNull Task<Location> task) {
                    if(task.isSuccessful()){
                        Location location = task.getResult();
                        Log.i("tag", "Provider:" + location.getProvider());
                        Log.i("tag", "Accuracy:" + location.getAccuracy());
                        Log.i("tag", "Latitude:" + location.getLatitude() + ", Longitude:" + location.getLongitude());
                        Log.i("tag", "Accuracy:" + location.getTime());
                    }else{
                        Log.e("tag", "Exception" + task.getException().getMessage());
                    }
                }
            });
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == RC_LOCATION_REQUEST && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            checkPermissionAndRequestLocation();
        }
    }

Get User Location Changes Update

If the purpose of the app is to track user location changes continuously then we can request fused location client to provide location changes. Location updates are received in a callback that we define in LocationRequest.

Let’s create location request with parameters for location provider client.

    private void setUpLocationRequest() {
        LocationRequest locationRequest = LocationRequest.create();
        locationRequest.setInterval(10000);
        locationRequest.setFastestInterval(5000);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

Check location settings

    private void checkLocationSettingsRequest(){

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest);

        SettingsClient locationClient = LocationServices.getSettingsClient(this);
        Task<LocationSettingsResponse> locationSettings = locationClient.checkLocationSettings(builder.build());

        locationSettings.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
            @Override
            public void onComplete(@NonNull Task<LocationSettingsResponse> task) {
                if(!task.isSuccessful()){
                    Log.e("tag", "Exception" + task.getException().getMessage());
                    if(task.getException() instanceof ResolvableApiException){
                        // show permission request to user
                        try {
                            ResolvableApiException resolvable = (ResolvableApiException) task.getException();
                            resolvable.startResolutionForResult(MainActivity.this,
                                    RC_LOCATION_ON_REQUEST);
                        } catch (IntentSender.SendIntentException sendEx) {
                            // Ignore the error.
                        }
                    }
                }else{

                }
            }
        });
    }

In the above snippet we call checkLocationSettings method to check if the location settings are correct. If the user needs to turn on the gps then it resolves the activity to turn on location. The result is received in onActivityResult. If the result is ok then we can we can start location request update.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == RC_LOCATION_ON_REQUEST && resultCode == Activity.RESULT_OK){
            Log.e("tag", "Resolution done");
            // call location update from here
        }
    }

Location Update Callback

Define location callback which will be called by the fused client with location data based on the timer set in location settings parameters.

    private void setUpLocationUpdatesCallback() {
        locationUpdatesCallback = new LocationCallback(){
            @Override
            public void onLocationResult(LocationResult locationResult) {
                if(locationResult!=null){
                    for(Location location: locationResult.getLocations()){
                        Log.i("tag", "Provider:" + location.getProvider());
                        Log.i("tag", "Accuracy:" + location.getAccuracy());
                        Log.i("tag", "Latitude:" + location.getLatitude() + ", Longitude:" + location.getLongitude());
                        Log.i("tag", "Time:" + location.getTime());
                    }
                }else{
                    Log.i("tag", "Location null");


                }
            }
        };
    }

You can add this code to start receiving location updates.

Add ACCESS_FINE_LOCATION in AndroidManifest.xml since we are expecting high accuracy data in location.

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

Check if we have the permission to request location updates. If we have the permission call Fused Location Client requestLocationUpdates method with callback as the parameter to start receiving updated. Remember to remove the callback when updates are no more required. The optimal place to call removeLocationUpdates is onPause.

    @Override
    protected void onResume() {
        super.onResume();
        startLocationUpdates();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mLocationProviderClient.removeLocationUpdates(locationUpdatesCallback);
    }

    private void startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }, RC_LOCATION_REQUEST );
        }else {
            mLocationProviderClient.requestLocationUpdates(locationRequest, locationUpdatesCallback, null);

        }
    }

 

 

Leave a Reply