Awareness API: What Is It and How It May Help?

jullsanders

JullSanders

Posted on March 1, 2020

Awareness API: What Is It and How It May Help?

Every 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 the purpose.

What is API in app development and how it may help?

Google Awareness API allows us to monitor the user activity, it’s possible at a certain moment as well as while the app operates.

API allows us to get the data as to the:

  • Headphones state (plugged/unplugged);

  • Location;

  • Activity (stands, drives, runs, walks);

  • Time (local user’s time o 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 him to visit the restaurant when he is somewhere nearby.

Awareness API is divided into two parts, namely:

*Snapshot API *— it allows to get the live info at a certain moment
*Fence API *— it registers one or several triggers, which inform us if the user is now active or not.
To better understand it, please find the example of an app code 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 your project. It’s like this:

 <meta-data
    android:name="com.google.android.awareness.API_KEY"
     android:value="YOUR_API_KEY"/>
</application>
Enter fullscreen mode Exit fullscreen mode

Now you have only to add dependency to gradle:

implementation 'com.google.android.gms:play-services-awareness:{last_version}'
Enter fullscreen mode Exit fullscreen mode

Don’t forget about the permissions, you should add the following to the manifest for the purpose:

<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
Enter fullscreen mode Exit fullscreen mode

*Don’t also forget about the permissions checking in the app.

That’s all, now you can use the possibilities of Awareness API in full.

Snapshot API

As it was already mentioned Snapshot API informs about the live status.

You should first initialize the SnapshotClient.

al snapshotClient = Awareness.getSnapshotClient(this)
Enter fullscreen mode Exit fullscreen mode

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 headphones, whether they are plugged in or unplugged. It will be useful for sports apps development, for instance, to notify the user about his goal achievement, if his headphones are plugged in.

To get to know the headphones state, you should just call the function getHeadphoneState() and to get the result to add addOnSuccessListener, which will turn us back the HeadphoneStateResponse, with the headphoneState. Further on getState - will return us «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:

private fun snapshotCheckHeadphones() {
        snapshotClient.headphoneState
            .addOnSuccessListener {
                snapshotHeadphonesContainer.text = it.headphoneState.toString(this)
            }
            .addOnFailureListener {
              handleSnapshotError(snapshotHeadphonesContainer, it)
            }
    }
Enter fullscreen mode Exit fullscreen mode

toString - this is the expanding feature to make the code look simpler.

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
            )
        }
    )
}
Enter fullscreen mode Exit fullscreen mode

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 he is interested in it and is somewhere nearby.

To get location you should call getLocation() in OnSuccess 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:

private fun snapshotGetLocation() {
        snapshotClient.location
            .addOnSuccessListener {
                with(it.location) {
                    snapshotLocationContainer.text = getString(
                        R.string.user_location,
                        latitude, longitude, altitude, accuracy
                    )
                } 
            }
            .addOnFailureListener {
                handleSnapshotError(snapshotLocationContainer, it)
            }
    }
Enter fullscreen mode Exit fullscreen mode

*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 it was already mentioned, Awareness API also allows to check the current user activity. It can be extremely useful in the fitness app development or some app with news. When the user does not move he can be offered to read some article.

The realization approach is the same: we need to call getDetectedActivity feature, which in case of success will turn us DetectedActivityResponse back. From it we can take data about the user activity. We have the following features available: getMostProbableActivity, which will return us the most probable activity and getProbableActivities, which will return us the 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 got due to the getConfidence() feature — it will return int value from 0 to 100.

Example:

snapshotClient.detectedActivity
            .addOnSuccessListener {
                with(it.activityRecognitionResult) {
                    snapshotActivityContainer.text = getString(
                        R.string.user_activity,
                        mostProbableActivity.stateString(),
                        mostProbableActivity.confidence
                    )
                }
            }
            .addOnFailureListener {
                handleSnapshotError(snapshotActivityContainer, it)
            }
Enter fullscreen mode Exit fullscreen mode

stateString - it’s the function of extension, which returns the text value of the activity type.

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()
    }
}
Enter fullscreen mode Exit fullscreen mode

Fence API

Awareness API allows to put certain conditions and «listen» when the activity of the users coincides with it.

We can check:

  • The location of a user and check if he entered a certain area.

  • The user activity when he or she, for instance, has started/continues/stopped to walk, run, drive, 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 in an evening time,without activity (so the user is likely in bed).

How to start using Fence.

Firstly, to get the information about the fence state change we should create our own BroadcastReceiver.

Like this for example:

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
                    }
                 }
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

It 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, which came coincides with the one we have registered (what’s it and where it’s got 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 vice versa and the UNKNOWN state means an error has occurred and the system fails to understand what the headphones’ status is.
    **Note: **don’t forget to register FenceReceiver in onCreate

registerReceiver(fenceReceiver, IntentFilter(FENCE_RECEIVER_ACTION))
Enter fullscreen mode Exit fullscreen mode

And to disconnect it at onDestroy:

unregisterReceiver(fenceReceiver)
Enter fullscreen mode Exit fullscreen mode

For the system to send us changes, we should create PendingIntent.

val intent = Intent(FENCE_RECEIVER_ACTION)
        val mPendingIntent =
            PendingIntent.getBroadcast(this, 0, intent, 
PendingIntent.FLAG_UPDATE_CURRENT)
Enter fullscreen mode Exit fullscreen mode

Then we should define which activity we are interested in. Let’s take the headphones plugged in and running for example.

val fence = AwarenessFence.and(HeadphoneFence.during(HeadphoneState.PLUGGED_IN), DetectedActivityFence.during(DetectedActivityFence.RUNNING))
Enter fullscreen mode Exit fullscreen mode

Now we gather it all together and register.

fenceClient.updateFences(
            FenceUpdateRequest.Builder().addFence(
                FENCE_KEY,
                fence,
                mPendingIntent
            ).build()
        )
            .addOnSuccessListener {
                //Fence created
            }
            .addOnFailureListener {
// Error while creating
            }
Enter fullscreen mode Exit fullscreen mode

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 the purpose, where the necessary FENCE_KEY is rendered as a parameter.

fenceClient.updateFences(
            FenceUpdateRequest.Builder()
                .removeFence(FENCE_KEY).build()
        )
Enter fullscreen mode Exit fullscreen mode

*if it’s necessary, you can also add successListener and failureListener for deleting.

Now knowing how to create and delete fence we can look at what types of fence exist.

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 the so-called «locations» and as soon as the user enters them we’ll know about it. We can check if he has entered/left a certain area or stays 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).

AwarenessFence inLocationFence = LocationFence.in(
latitude, longitude, radius, timeInMillis); 
AwarenessFence exitingLocationFence = LocationFence.exiting(
latitude, longitude, radius); 
AwarenessFence enteringLocationFence = LocationFence.entering(
latitude, longitude, radius);
Enter fullscreen mode Exit fullscreen mode

Activity Fence

We can also get to know when a user has started, continues or finished a certain activity. The class DetectedActivityFence, is used for the 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:

AwarenessFence running = DetectedActivityFence.during(DetectedActivity.RUNNING);
 AwarenessFence startRunning = DetectedActivityFence.starting(DetectedActivity.RUNNING);
 AwarenessFence stopRunning = DetectedActivityFence.stopping(DetectedActivity.RUNNING);
Enter fullscreen mode Exit fullscreen mode

Time Fence

We can create fence for a certain period of time or a certain day.

AwarenessFence workingHoursFence = TimeFence.inInterval(startTime, endTime);
AwarenessFence fridayFence = TimeFence.inFridayInterval(
                                      timeZone, startTime, endTime);
Enter fullscreen mode Exit fullscreen mode

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.

Originally published at https://stfalcon.com .

💖 💪 🙅 🚩
jullsanders
JullSanders

Posted on March 1, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related