SDK Location Component

Permissions

Access to the user's location information requires proper permissions. As per Android guidelines, it's important to provide a clear and comprehensive rationale to the user about how the location information will be used in the app. This can be achieved through presenting a permission request dialog.

For a more in-depth understanding of the permissions on Android, kindly refer to the official Android documentation: Permissions on Android and Requesting Location Permissions.

User Location

To get the user’s location, we need to:

  1. Retrieve an instance of LocationComponent

  2. Build location request that specifies location accuracy and intervals

  3. Implement LocationCallback

  4. Get a location engine

  5. Request for location updates

  6. Receive location in the callback.

  7. Display user location

Retrieve LocationComponent

The LocationComponent in Android Maps SDK is an object that provides access to device's location information, including the latitude, longitude, and accuracy. To retrieve the LocationComponent, you need to access the associated NextbillionMap of a MapView. This can be done by calling the getLocationComponent() method on the NextbillionMap instance. The returned LocationComponent object can be used to get the device's current location information and configure various settings related to the location display on the map.

1
LocationComponent locationComponent = nextbillionMap.getLocationComponent();

Build Location Request

The method "buildEngineRequest" builds and returns a LocationEngineRequest object. It takes two parameters, "UPDATE_INTERVAL_IN_MILLISECONDS" and "FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS", which set the desired frequency of location updates in milliseconds.

1
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
2
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500;
3
4
private LocationEngineRequest buildEngineRequest() {
5
return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS) .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
6
.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS)
7
.build();
8
}

The LocationEngineRequest is built using the LocationEngineRequest.Builder class and the parameters set include a desired update interval of 1000 milliseconds and the highest accuracy priority, as well as the fastest possible interval of 500 milliseconds. This LocationEngineRequest object is used to request location updates from the device's GPS.

For more details about the location update intervals, please refer to Google’s LocationRequest.

Implement LocationCallback

1
private static class NavigationLocationCallback implements LocationEngineCallback<LocationEngineResult> {
2
3
@Override
4
public void onSuccess(LocationEngineResult result) {
5
Location location = result.getLastLocation();
6
if (location == null) {
7
return;
8
}
9
//this is where you handle the received location
10
}
11
}
12
13
@Override
14
public void onFailure(@NonNull Exception exception) {
15
Timber.e(exception);
16
}
17
}

This code defines an implementation of the LocationEngineCallback interface, which is used to receive the result of a location request. When the location request is successful, the onSuccess method is called with the LocationEngineResult that contains the last known location. The code checks if the location is null, if it is, the method returns. If the location is not null, the code handles the received location. In case of failure during the location request, the onFailure method is called with the exception that was thrown. The code logs the exception using the Timber library.

Obtain LocationEngine and request for update

This code below obtains a LocationEngine instance and sets it up to receive location updates. The code calls the LocationEngineProvider.getBestLocationEngine method to get the best available location engine for the device, then builds a LocationEngineRequest with desired update interval and priority. Finally, the code requests location updates from the engine and also requests the last known location. The location updates and the last known location will be handled by the NavigationLocationCallback class, which implements the LocationEngineCallback interface.

1
private final NavigationLocationCallback callback = new NavigationLocationCallback(this);
2
3
private void obtainLocationEngine() {
4
locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext());
5
LocationEngineRequest request = buildEngineRequest();
6
locationEngine.requestLocationUpdates(request, callback, null);
7
locationEngine.getLastLocation(callback);
8
}
9
10
11
public void onResume() {
12
super.onResume();
13
mapView.onResume();
14
if (locationEngine != null) {
15
locationEngine.requestLocationUpdates(buildEngineRequest(), callback, null);
16
}
17
}
18
19
@Override
20
public void onPause() {
21
super.onPause();
22
mapView.onPause();
23
if (locationEngine != null) {
24
locationEngine.removeLocationUpdates(callback);
25
}
26
}

Receive location and display

As mentioned previously, we will receive location in LocationCallback, after we receive the latest location, we can pass it to LocationComponent

1
@Override
2
public void onSuccess(LocationEngineResult result) {
3
Location location = result.getLastLocation();
4
if (location == null) {
5
return;
6
}
7
//this is where you handle the received location
8
locationComponent.forceLocationUpdate(location);
9
}
10
}

This code is handling the successful receipt of a location in the LocationEngineResult. When the latest location is received, it is passed to the LocationComponent through the forceLocationUpdate method. This ensures that the LocationComponent is updated with the latest location information.

Built-in Location Engine

As described in previous section, this is how we obtain an instance of location engine

1
LocationEngineProvider.getBestLocationEngine(getApplicationContext());

The LocationEngineProvider will check whether you have google service and decide which location engine to return.

There are two built-in Location engines:

  • One is built on Google’s Fused location provider, but this will depend on the google location service.
  • The other one uses Core Android Location, which doesn’t need external dependencies

How to check if there has a google location service:

Check if these two class names are on the classpath

  • "com.google.android.gms.location.LocationServices"
  • "com.google.android.gms.common.GoogleApiAvailability"
1
/**
2
* Checks if the class is on classpath
3
* @param className of the class to check.
4
* @return true if the class is on the classpath, false otherwise.
5
*/
6
static boolean isOnClasspath(String className) {
7
boolean isOnClassPath = true;
8
try {
9
Class.forName(className);
10
} catch (ClassNotFoundException exception) {
11
isOnClassPath = false;
12
}
13
return isOnClassPath;
14
}

Custom Location Engine

Developers are not limited to the built-in location engine, they can also build their implementations of the location engine, which means developers can build their location service or location simulation service to fulfill their business needs.

To create a custom location engine, you can choose to implement your location provider that returns an Android Location or choose to implement LocationEngine.

To request location from Nextbillion.AI’s LocationEngine, we need to instantiate the built-in LocationEngineCallabck and LocationEngineRequest, which means we need to handle the conversion between the actual location provider’s request, result, and callback in the custom implementation of LocationEngine. (A location provider can be Core Android Location, Google Location Service, or other location service libraries.)

1
public interface LocationEngine {
2
3
/**
4
* Returns the most recent location currently available.
5
* If a location is not available, which should happen very rarely, null will be returned.
6
*/
7
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
8
void getLastLocation(@NonNull LocationEngineCallback<LocationEngineResult> callback) throws SecurityException;
9
10
/**
11
* Requests location updates with a callback on the specified Looper thread.
12
*/
13
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
14
void requestLocationUpdates(@NonNull LocationEngineRequest request,
15
@NonNull LocationEngineCallback<LocationEngineResult> callback,
16
@Nullable Looper looper) throws SecurityException;
17
18
/**
19
* Requests location updates with callback on the specified PendingIntent.
20
*/
21
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
22
void requestLocationUpdates(@NonNull LocationEngineRequest request,
23
PendingIntent pendingIntent) throws SecurityException;
24
25
/**
26
* Removes location updates for the given location engine callback.
27
* It is recommended to remove location requests when the activity is in a paused or stopped state
28
*/
29
void removeLocationUpdates(@NonNull LocationEngineCallback<LocationEngineResult> callback);
30
31
/**
32
* Removes location updates for the given pending intent.
33
* It is recommended to remove location requests when the activity is in a paused or stopped state
34
*/
35
void removeLocationUpdates(PendingIntent pendingIntent);
36
}
37

© 2024 NextBillion.ai all rights reserved.