The Android SDK Guide Follow
The Meridian Android SDK has all the tools you’ll need to embed the Meridian Editor’s maps, turn-by-turn navigation, indoor location awareness, and notifications into your own custom Android app.
Once you’ve added maps, routes, and placemarks to the Meridian Editor, you can use the Meridian SDK to integrate that content into your Meridian-powered Android app.
Go here for the Meridian Android SDK Reference documentation.
Go here to download the latest version of the Android SDK.
The Meridian Samples App
The Meridian Samples app is included with the Android SDK to demonstrate common Meridian features and workflows.
Add the SDK to Your Project
In order to simplify using the Meridian SDK library with your Android project, we’ve bundled our SDK code into a binary distribution of the Android Library Project (AAR) file.
The Meridian SDK supports devices with Android 8.0+ (Oreo) API Level 26 and higher.
The Meridian SDK targets the latest version of Android
Add the AAR Relative Path
Complete these steps to add the AAR file to your Android project.
-
Choose a location for
meridian-x.y.z.aar
. -
Edit your app’s
build.gradle
file to add the relative path to themeridian-x-y-z.aar
file location insideflatDir { }
, where our app will look for dependencies. Intorepositories { }
, insert:
repositories { google() mavenCentral() // Tell gradle to look in our parent directory for the meridian AAR package. flatDir { dirs '[relative file path to the AAR directory]' } }
Add Dependencies
To use the Meridian SDK classes in your project, add the implementation information for the dependencies to the build.gradle
file. These are the meridian-x.y.z.aar file and two required external dependencies.
To find the project’s current dependencies, look in build.gradle
in the MeridianSamples directory.
In the build.gradle
file inside dependencies { }
, insert implementation
for the meridian-x.y.z.aar file and the three required external dependencies:
dependencies {
implementation 'com.arubanetworks.meridian:meridian:x.y.z@aar' // Google Support Libraries implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.appcompat:appcompat:1.4.0' // Required for GPS on newer Android devices. implementation 'com.google.android.gms:play-services-location:18.0.0'
implementation 'com.google.android.material:material:1.7.0'
// The SDK also has these external dependencies that you'll need to include:
implementation 'com.android.volley:volley:1.2.1'
implementation 'com.squareup:otto:1.3.8'
implementation 'org.conscrypt:conscrypt-android:2.5.2'
implementation 'org.greenrobot:eventbus:3.3.1'
implementation 'com.lemmingapex.trilateration:trilateration:1.0.2'
}
Import Packages
When this is done, you’ll be able to import the com.arubanetworks.meridian
packages to your project and use Meridian classes in your source files.
The SDK’s MeridianSamples/app
project folder has an example of what the finished build.gradle
file should look like.
Add Permissions
To enable the Meridian SDK’s location-awareness features, add the following permissions to your project’s AndroidManifest.xml
file:
<!-- For using GPS and Location in general -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- For using location derived from bluetooth beacons -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- For using location derived from bluetooth beacons on Android 12 and later -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN/>
To enable Meridian SDK's location-aware features (e.g. location sharing) in the background, add the following permission to your project’s AndroidManifest.xml
file and request the permission from the user as required for the Android version:
<!-- For using bluetooth in the background -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Configure the SDK
Before you can use the features of the Meridian SDK, you’ll need to create an instance of MeridianConfig
. This will configure the SDK.
Meridian uses token-based authentication. In order for your Meridian-powered app to communicate with the Editor, you’ll need to specify a Meridian token when initializing the SDK.
Put the following line in the onCreate
method of your Application
class or main activity.
// Configure Meridian Meridian.configure(this, YOUR_EDITOR_TOKEN);
Using Editor Keys
Use instances of EditorKey to specify apps, maps, and placemarks that have been created in the Meridian Editor. Most of the Meridian SDK classes require a valid key during initialization.
// Create a key representing your app in the Meridian Editor. EditorKey appKey = new EditorKey("5809862863224832"); // Create a key representing a map in the Meridian Editor. EditorKey mapKey = EditorKey.forMap("5668600916475904", appKey.getId()); // Create a key representing a placemark. EditorKey placemarkKey = EditorKey.forPlacemark("5668600916475904_5709068098338816", mapKey);
When you create an EditorKey to represent a map, the app identifier you provide becomes the parent of the map key. Likewise, when you create a placemarkKey, the map you specify becomes the parent of that placemark.
EditorKey placemarkKey = EditorKey.forPlacemark("375634485771", someMapKey); EditorKey mapKey = placemarkKey.getParent(); Log.i(TAG, "My map ID: " + mapKey.getId()); EditorKey appKey = mapKey.getParent(); Log.i(TAG, "My app ID: " + appKey.getId());
Display Maps
You can use MapFragment to provide a self-contained interface for maps and directions. Simply initialize the fragment with a valid EditorKey:
// Create a key representing your app in the Meridian Editor. EditorKey appKey = new EditorKey("5809862863224832"); // Create a key representing a map in the Meridian Editor. EditorKey mapKey = EditorKey.forMap("5668600916475904", appKey.getId()); MapFragment mapFragment = new MapFragment.Builder().setMapKey(mapKey).build();
MapFragment hosts a MapView and implements the MapView.MapViewListener interface, handling the basic tasks delegated by MapView.
You can also use MapView directly in your own activity or fragment, optionally implementing methods defined by the MapView.MapViewListener interface so that your activity can respond to MapView events.
Call the setMapKey() method to choose the map to display.
NOTE: We strongly advise using MapFragment whenever possible. If you decide to use a MapView independently, you must always pass your activity’s pause/resume/destroy events to the MapView to ensure resources are managed properly.
// Using pause/resume/destroy events with a MapView in your activity private MapView mapView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EditorKey appKey = new EditorKey("5809862863224832"); mapView = new MapView(this);
mapView.setAppKey(appKey); // If you want to handle MapView events mapView.setListener(this); // Set the map to load mapView.setMapKey(EditorKey.forMap("5668600916475904", appKey.getId())); // Assume myLayout is this activity's root view myLayout.addView(mapView); } @Override protected void onResume() { super.onResume(); // MapView needs to know when its host activity is resumed mapView.onResume(); } @Override protected void onPause() { super.onPause(); // MapView needs to know when its host activity is paused mapView.onPause(); } @Override protected void onDestroy() { super.onDestroy(); // MapView needs to know when its host activity is destroyed mapView.onDestroy(); }
Load Directions
MapFragment handles loading and presenting directions in response to user interaction. When you create the map fragment, include the pendingDestination
parameter to present directions to a placemark when direction-finding resumes.
If you’re using MapView directly in your activity, you’ll need to load the directions manually with the Directions class.
To do so, first ensure that your activity implements the Directions.DirectionsRequestListener interface so that it can handle the results of the directions request. Use a Directions.Builder instance to configure the details of the desired route. To do this, specify the start and end points for the route using instances of DirectionsSource
and DirectionsDestination
, which contain information about a point or placemark on a map.
Next, call build()
to create the Directions
object from the builder.
Finally, call calculate()
to start the directions process.
The Directions
object will call onDirectionsComplete()
after successful completion or onDirectionsError()
if something went wrong.
In the following code example, MeridianLocation is the source of the directions.
A new route is calculated when the user’s blue dot location is approximately 10 meters from the route. To customize the reroute distance, you can use
Meridian.getShared().setRerouteDistance()
.
Related to this, you can also use
Meridian.getShared().setRouteSnapDistance()
to configure the distance from the route at which the user's blue dot will be "snapped" to the determined route. This value is 5 meters by default.
// In your Activity private static final EditorKey appKey = new EditorKey("YOUR_APP_KEY"); private void getDirections(MeridianLocation source, Placemark destination) { Directions.Builder directionsBuilder = new Directions.Builder() .setAppKey(appKey) .setSource(DirectionsSource.forMapPoint(source.getMap(), source.getPoint())) .setDestination(DirectionsDestination.forPlacemarkKey(destination.getKey())) .setTransportType(TransportType.WALKING) .setListener(this); Directions directions = directionsBuilder.build(); directions.calculate(); } @Override public void onDirectionsComplete(DirectionsResponse response) { if (response.getRoutes().size() 0) { // Normally only one route will be returned Route route = response.getRoutes().get(0); // If we have a MapView we can tell it to display this route myMapView.setRoute(route); } }
If a current location isn’t available, you may want to prompt the user to choose a starting location with SearchActivity.
In the example, SearchActivity and startActivityForResult()
will prompt the user to choose a starting placemark.
// In your Activity private Directions.Builder directionsBuilder; private static final EditorKey appKey = new EditorKey("5085468668573440"); public static final int PLACEMARK_PICKER_CODE = 42; private void getDirections(Placemark placemark) { directionsBuilder = new Directions.Builder() .setContext(this) .setAppKey(appKey) .setDestination(DirectionsDestination.forPlacemark(placemark)) .setTransportType(TransportType.WALKING) .setListener(this); // start a search Activity to get the starting point for the route startActivityForResult(SearchActivity.createIntent(this, appKey), PLACEMARK_PICKER_CODE); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // Now that the user picked a placemark to start from, we can calculate the route if (requestCode == PLACEMARK_PICKER_CODE) { if (resultCode == Activity.RESULT_OK) { LocalSearchResult result = (LocalSearchResult) data.getSerializableExtra(SearchActivity.SEARCH_RESULT_KEY); Placemark source = result.getPlacemark(); directionsBuilder.setSource(DirectionsSource.forPlacemark(source)); directions = directionsBuilder.build(); directions.calculate(); } } }
Get a User’s Location
A user’s most recent location can be retrieved with the LocationRequest class. This request is asynchronous.
private LocationRequest request = null; private static final EditorKey appKey = new EditorKey("5809862863224832"); @Override public void onResume() { super.onResume(); request = LocationRequest.requestCurrentLocation(getActivity(), appKey, new LocationRequest.LocationRequestListener() { @Override public void onResult(MeridianLocation location) { // Update UI with new Location } @Override public void onError(LocationRequest.ErrorType location) { // Notify user that there was an error retrieving the location } }); } @Override public void onPause() { if (request != null && request.isRunning()) { request.cancel(); request = null; } super.onPause(); }
Get Continuous Updates About a User’s Location
MeridianLocationManager determines the user’s location by gathering all available location data for your Meridian-powered app. Implement the MeridianLocationManager.LocationUpdateListener interface to get callbacks as new locations are gathered.
// In an Activity that implements the LocationUpdateListener interface private static final EditorKey appKey = new EditorKey("5809862863224832"); private MeridianLocationManager locationHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); locationHelper = new MeridianLocationManager(this, appKey, this); // Build out the UI ... } @Override protected void onStart() { locationHelper.startListeningForLocation(); super.onStart(); } @Override protected void onStop() { locationHelper.stopListeningForLocation(); super.onStop(); } @Override public void onLocationUpdate(MeridianLocation location) { // Update the UI with the new location } @Override public void onLocationError(Throwable tr) { // Update the UI to inform the user that their location could not be determined. }
Location Sharing
Location sharing lets users share their location with each other.
Prerequisites
Location Sharing needs to be enabled by an admin in the Meridian Editor before you can use it in the SDK. If you’d like to enable Location Sharing, please email hpe-aruba-meridian@hpe.com.
If you haven’t already done so, you’ll need to generate a valid token in the Editor. To generate one, in the sidebar menu click Permissions, and then click Application Tokens. Click Add Application + to generate a token for your app. You can name it anything.
When configuring the Meridian SDK, set the application token you generated in the Editor:
LocationSharing.init("kd84hf83ck93k39dyi3nxo3mf94");
For best results, call init
from your Application class.
LocationSharing
LocationSharing
is the main access point to the Location Sharing API. Use the User
, Friend
, Invite
, and Location
classes to get the Location Sharing data.
Create Accounts
// Creates a location sharing user. All users require a first name. Last name is optional. User sampleUser = new User(); sampleUser.setFirstName("Sample User"); LocationSharing.shared().createUser(sampleUser, new LocationSharing.Callback
Start Location Sharing
LocationSharing.shared().startPostingLocationUpdates(applicationContext);
Stop Location Sharing
LocationSharing.shared().stopPostingLocationUpdates(applicationContext);
Check Location Sharing Status
LocationSharing.shared().isUploadingServiceRunning() // example: button that performs start and stop sharing location if (LocationSharing.shared().isUploadingServiceRunning()) { LocationSharing.shared().stopPostingLocationUpdates(applicationContext); } else { LocationSharing.shared().startPostingLocationUpdates(applicationContext); }
Start and Stop Location Sharing Listener
LocationSharing.shared().addListener(new LocationSharing.Listener() { @Override public void onPostingLocationUpdatesStarted() { // ... } @Override public void onFriendsUpdated(List
Create an Invite
Invitations expire after 7 days.
LocationSharing.shared().createInvite(new LocationSharing.Callback
Get the Current Friend List
LocationSharing.shared().getFriends(new LocationSharing.Callback
createInvite and getFriends
LocationSharing
keeps a copy of the current user, for use by calls like createInvite
and getFriends
. The implementor is responsible for storing the current user and setting it to the LocationSharing
object.
When an account is created, the new user is automatically set to the current user.
Store the New User
After creating the new user, store it:
LocationSharing.shared().createUser(newUser, new LocationSharing.Callback
Set the Current User
If a user restarts the app, the current user needs to be set again. This is equivalent to a login operation.
LocationSharing.shared().setCurrentUser(OurOwnStorage.retrieveLocationSharingUser());
Using Local Search
You can use the LocalSearch classes to find points of interest near a user’s location. You’ll usually use this in conjunction with MeridianLocationManager so that you can provide a location and nearby placemarks.
For best performance, limit local search results to 20 or less.
// This Activity implements the LocalSearch.LocalSearchListener interface private void findNearbyCafe() { LocalSearch localSearch = new LocalSearch.Builder() .setQuery("Cafe") .setApp(appKey) .setLocation(locationManager.getLocation()) .setListener(this) .setLimit(20) .build(); localSearch.start(); } @Override public void onSearchComplete(LocalSearchResponse response) { for (LocalSearchResult result : response.getResults()) { Log.i(TAG, String.format("%s is %f seconds away", result.getPlacemark().name, result.time / 1000)); } } @Override public void onSearchError(Throwable tr) { Log.e(TAG, "Search error", tr); }
Asset Tracking
Asset Tracking is a feature that uses Aruba Tags hardware to track valuable locations on a map. You can use the SDK to get Tag location updates and render Tag locations on a map.
Get Tag Updates
Before you can get Tag updates, you’ll need to create an instance of Asset Tracking’s main class, TagStream
.
First, create your own instance of TagStream
using its Builder
:
tagStream = new TagStream.Builder() .setMapKey(yourMapKeyHere) .setListener(this) .build();
With the TagStream
instance created, call the following method to get updates on your tagged assets:
tagStream.startUpdatingTags();
To stop getting updates:
tagStream.stopUpdatingTags();
The TagStream
builder class takes a listener that will be used to pass information about Tags to your code. The listener must implement two methods:
void onTagsUpdated(List
The first method will be called when we get information about new Tags or when existing Tags are updated. This list of Tags will contain all Tags.
The second method will get called when a Tag is removed. This list of Tags will contain the deleted Tags.
To dispose of the TagStream
:
tagStream.dispose();
Render Tags on the Map
Use the marker TagMarker
to render your Tags on a map. It will show a generic asset icon. Create a marker in the following way:
tagMarker = new TagMarker(getContext(), tag);
The marker gets the name and position of the marker from the tag
object. At that point, you can add it to your map.
You can find working examples of this in the Samples app with TagsFragment
and SingleTagFrament
.
Comments
0 comments
Please sign in to leave a comment.