Awareness API: What Is It and How It May Help?
Learn when Awareness API may be of use in mobile app development, in what way, and how to implement it in a project.
Join the DZone community and get the full member experience.
Join For FreeEvery year our life and daily routine are more and more closely connected with mobile phones. Modern life is extremely dynamic and that’s why mobile apps should match the users’ activity. Awareness API exists just for that purpose.
What Is This API?
Google Awareness API allows us to monitor user activity. The API allows us to get data related to the user's:
- headphone state (plugged/unplugged).
- location.
- activity (standing, driving, running, walking).
- time (local user’s time to set certain frames).
- reaction to beacons.
There are plenty of situations where these features can be used. If it’s a sports app for running, for instance, it’s possible to find out when the user started his training, and if it’s a restaurant app, there is an opportunity to notify the user about special offers or invite them to visit the restaurant when they are somewhere nearby.
The Awareness API is divided into two parts, namely:
- Snapshot API — it allows to get live info at a certain moment.
- Fence API — it registers one or several triggers, which inform us if the user is active or not.
To better understand, you can run through the code on GitHub here: https://github.com/stfalcon-studio/GoogleAwarenessDemo.
To begin we should get an API key, here is a perfect guide from Google: https://developers.google.com/awareness/android-api/get-a-key.
As soon as we’ve got the key, we should add it to the manifest file of our project. It looks like this:
<application>
<meta-data
android:name="com.google.android.awareness.API_KEY"
android:value="YOUR_API_KEY"/>
</application>
Now you only have to add a dependency to Gradle:
xxxxxxxxxx
implementation 'com.google.android.gms:play-services-awareness:{last_version}'
Don’t forget about the permissions; you should add the following to the manifest for that purpose:
xxxxxxxxxx
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
*Don’t also forget about permissions checking in the app.
That’s all, now you can use the Awareness API in full.
Snapshot API
As I mentioned earlier, the Snapshot API informs about a users's live status.
You should first initialize the SnapshotClient.
xxxxxxxxxx
al snapshotClient = Awareness.getSnapshotClient(this)
Now we can get data about the user’s activity right at the moment.
Headphones
With a Snapshot API we can find the current state of a user's headphones, i.e. whether they are plugged in or unplugged. This can be useful for sports apps development, for instance, to notify the user about their goal achievement, if their headphones are plugged in.
To know the headphones' state, you should just call the function getHeadphoneState()
. To get the result, add addOnSuccessListener
, which will turn us back the HeadphoneStateResponse
, with the headphoneState
. Further on, getState
will return 1 or 2, which correspond to the status PLUGGED_IN
or UNPLUGGED
.
It’s also reasonable to add addOnFailureListener
, which returns Exception
if something has gone wrong.
Example:
xxxxxxxxxx
private fun snapshotCheckHeadphones() {
snapshotClient.headphoneState
.addOnSuccessListener {
snapshotHeadphonesContainer.text = it.headphoneState.toString(this)
}
.addOnFailureListener {
handleSnapshotError(snapshotHeadphonesContainer, it)
}
}
toString
- this is the expanding feature to make the code look simpler.
xxxxxxxxxx
fun HeadphoneState.toString(context: Context): String {
return context.getString(
R.string.headphones_state,
if (state == HeadphoneState.PLUGGED_IN) {
context.getString(R.string.headphones_state_connect)
} else {
context.getString(
R.string.headphones_state_disconnected
)
}
)
}
Location
With the help of Snapshot API we can also find out the current user’s location.
The examples of the usage are numerous in this case. If, for instance, the app has a list of some places, we can offer the user to visit this or that place if they are interested in it and it's somewhere nearby.
To get the location you should call getLocation()
in OnSuccess
– after this we will get LocationResponse
, which contains information about the user’s locale. We can get the info with getLocation()
, which contains latitude, longitude, altitude, and so on.
Example:
xxxxxxxxxx
private fun snapshotGetLocation() {
snapshotClient.location
.addOnSuccessListener {
with(it.location) {
snapshotLocationContainer.text = getString(
R.string.user_location,
latitude, longitude, altitude, accuracy
)
}
}
.addOnFailureListener {
handleSnapshotError(snapshotLocationContainer, it)
}
}
Location
- it’s a standard class of the Android SDK, so you can check the manual for the detailed description of all the available functions.
Note: don’t forget to add `android permission ACCESS_FINE_LOCATION
` to the manifest as well as permission for checking.
User Activity
As I already mentioned, Awareness API also allows us to check the current user activity. This can be extremely useful in fitness or news apps.
The approach is the same: we need to call the getDetectedActivity
feature, which in case of success will return DetectedActivityResponse
. From this, we can take data about user activity. We have the following features available: getMostProbableActivity
, which will return the most probable activity and getProbableActivities
, which will return a list of possible activities sorted from the most probable one.
Activity has two parameters, namely:
- Activity type — we use
getType()
for getting the type of activity, the example will be below. - Probability of the activity — which is retreived via the
getConfidence()
feature — will return an int value from 0 to 100.
Example:
xxxxxxxxxx
snapshotClient.detectedActivity
.addOnSuccessListener {
with(it.activityRecognitionResult) {
snapshotActivityContainer.text = getString(
R.string.user_activity,
mostProbableActivity.stateString(),
mostProbableActivity.confidence
)
}
}
.addOnFailureListener {
handleSnapshotError(snapshotActivityContainer, it)
}
stateString
- it’s the extension function, which returns the text value of the activity type.
xxxxxxxxxx
fun DetectedActivity.stateString(): String {
return when (type) {
0 -> "IN_VEHICLE"
1 -> "ON_BICYCLE"
2 -> "ON_FOOT"
3 -> "STILL"
4 -> "UNKNOWN"
5 -> "TILTING"
6, 9, 10, 11, 12, 13, 14, 15 -> type.toString()
7 -> "WALKING"
8 -> "RUNNING"
16 -> "IN_ROAD_VEHICLE"
17 -> "IN_RAIL_VEHICLE"
18 -> "IN_TWO_WHEELER_VEHICLE"
19 -> "IN_FOUR_WHEELER_VEHICLE"
else -> type.toString()
}
}
Fence API
Awareness API allows us to put certain conditions and listen when the activity of the users coincide with it.
We can check:
- the location of a user and if they entered a certain area.
- the user's activity when they, for instance, are walking, running, driving, etc.
- headphones' state, when they have been plugged in or unplugged.
- when the user has entered the area of beacons operation.
- time frames, when the user is in a certain timeframe of a certain weekday.
We can also combine several features, using the operators AND, OR, or NOT. We can, for instance, check the following:
- The user runs with headphones plugged in.
- The user drives and has entered a certain area.
- The headphones are plugged in during the evening time, without activity (so the user is likely in bed).
How to Start Using Fence
Firstly, to get the information about Fence's state change we should create our own BroadcastReceiver
.
Like this for example:
xxxxxxxxxx
inner class FenceReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val fenceState = FenceState.extract(intent)
if (fenceState.fenceKey == FENCE_KEY) {
when (fenceState.currentState) {
FenceState.TRUE -> {
// We've entered the fence
}
FenceState.FALSE -> {
// We're not in the fence
}
FenceState.UNKNOWN -> {
// Something went wrong
}
}
}
}
}
Fence will receive all the changes, which refer to our registered fences. For instance, we wait till the user plugs the headphones in:
- We check if the
FENCE_KEY
coincides with the one we have registered (what it is and where it’s gotten from we’ll see below). - Then we check the state. If it’s TRUE, then the headphones are plugged in, if it’s FALSE, then the headphones are unplugged, and the UNKNOWN state means an error has occurred and the system failed to understand the headphones’ status.
Note: don’t forget to register FenceReceiver
in onCreate
registerReceiver(fenceReceiver, IntentFilter(FENCE_RECEIVER_ACTION))
And to disconnect it at onDestroy
:
unregisterReceiver(fenceReceiver)
For the system to send us changes, we should create PendingIntent
.
xxxxxxxxxx
val intent = Intent(FENCE_RECEIVER_ACTION)
val mPendingIntent =
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
Then we should define which activity we are interested in. Let’s take the headphones plugged in and running for example.
xxxxxxxxxx
val fence = AwarenessFence.and(HeadphoneFence.during(HeadphoneState.PLUGGED_IN), DetectedActivityFence.during(DetectedActivityFence.RUNNING))
Now we gather it all together and register.
xxxxxxxxxx
fenceClient.updateFences(
FenceUpdateRequest.Builder().addFence(
FENCE_KEY,
fence,
mPendingIntent
).build()
)
.addOnSuccessListener {
//Fence created
}
.addOnFailureListener {
// Error while creating
}
FENCE_KEY
is necessary for us to distinguish various registered fences.
You should also not forget about Fence deleting when we have finished working with it. We use removeFence()
for this purpose, where the necessary FENCE_KEY
is rendered as a parameter.
xxxxxxxxxx
fenceClient.updateFences(
FenceUpdateRequest.Builder()
.removeFence(FENCE_KEY).build()
)
*If it’s necessary, you can also add successListener
and failureListener
for deleting.
Now that we know how to create and delete Fence, we can look at what types exist in Fence.
Headphone Fence
With headphones, everything is alike and we have the following fences:
- AwarenessFence headphonesPluggedInFence = HeadphoneFence.during(HeadphoneState.PLUGGED_IN;
- AwarenessFence headphonesUnpluggedFence = HeadphoneFence.during(HeadphoneState.UNPLUGGED;
Location Fence
We can create so-called "locations" and as soon as the user enters them we’ll know about it. We can check if they have entered/left a certain area or stayed in it.
You need to specify the data about the latitude, longitude, and radius of the location (for checking if the user is inside the area, you should also indicate how many milliseconds should a user stay in it).
xxxxxxxxxx
AwarenessFence inLocationFence = LocationFence.in(
latitude, longitude, radius, timeInMillis);
AwarenessFence exitingLocationFence = LocationFence.exiting(
latitude, longitude, radius);
AwarenessFence enteringLocationFence = LocationFence.entering(
latitude, longitude, radius);
Activity Fence
We can know when a user started, continued, or finished a certain activity. The class DetectedActivityFence
is used for this purpose. It has the starting
, during
, and stopping
features. The type of activity is added to these features as a parameter. Let’s, for example, create Fences for all running states:
xxxxxxxxxx
AwarenessFence running = DetectedActivityFence.during(DetectedActivity.RUNNING);
AwarenessFence startRunning = DetectedActivityFence.starting(DetectedActivity.RUNNING);
AwarenessFence stopRunning = DetectedActivityFence.stopping(DetectedActivity.RUNNING);
Time Fence
We can create a Fence for a certain period of time or a certain day.
xxxxxxxxxx
AwarenessFence workingHoursFence = TimeFence.inInterval(startTime, endTime);
AwarenessFence fridayFence = TimeFence.inFridayInterval(
timeZone, startTime, endTime);
That’s all.
We have had an overlook what an API is and how to use Fences and Snapshots. Thanks to them we can create more flexible apps, which facilitate the user’s usage of the application.
Published at DZone with permission of Oleksandra Liubytska. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments