/ android

Device health matters in the world of location tracking

“Anything that can go wrong will go wrong” goes the old aphorism called Murphy’s law. Device health matters in the world of location tracking because Murphy lives in our world. If the happy path was the only path collecting accurate and battery-efficient location data would have been sufficient for location tracking. The real world presents a different picture though. Things start to break when the device loses network connectivity or gets powered off. To add to our woes users disable location services and GPS signals get flaky. In such situations it gets hard to reliably tell what happened in the life of the user. This post talks about how we use device health events to answer these questions. Furthermore we discuss how we use this data to optimize the use of device resources.

You will find this post relevant if you are building location features:

  1. without HyperTrack and dealing with similar reliability issues
  2. or with HyperTrack and want to get access to this data.

Device health events that we use

Device battery

User with Low device battery

It helps to know when the user’s device battery is low or about to die. Similarly it is useful to know when the device is charging. Overall plotting a device battery drain curve provides vital information about the user’s battery footprint and consumption patterns.

<receiver android:name="com.test.app.BatteryStatusChangedReceiver">
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
        <action android:name="android.intent.action.BATTERY_LOW"/>
        <action android:name="android.intent.action.BATTERY_OKAY"/>
public class BatteryStatusChangedReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        // Determine device's battery level
        Intent batteryIntent = mContext.getApplicationContext().registerReceiver(null,
                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        int rawLevel = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        double scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        double batteryLevel = -1;
        if (rawLevel >= 0 && scale > 0) {
            batteryLevel = (rawLevel / scale) * 100;
        // Detect device's charging status
        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                status == BatteryManager.BATTERY_STATUS_FULL;

In addition this data provides useful input to the variable frequency model for data collection and transmission. The primary purpose of this patent-pending model is to manage the battery efficiency of location tracking.

Network connectivity (including Airplane mode)

Users with network disabled

It helps to know when the network is offline and the reason why this is so. Listening to the device network connection status including Airplane mode changes makes it possible to distinguish between the user disabling network and patchy network conditions. If journaled efficiently on the device the server can get this information with accurate time stamps when the device is back online. In addition it is useful to get information about the type of network connection—cellular data or Wi-Fi. Wi-Fi networks are faster and unmetered and therefore preferred to fetch or transmit data when available.

<receiver android:name="com.test.app.NetworkStatusChangedReceiver">
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
        <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
public class NetworkStatusChangedReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        // Device's network connectivity status
        ConnectivityManager connectivityManager
                = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        boolean isInternetConnected = activeNetworkInfo != null && activeNetworkInfo.isConnected();

        // Device's wifi status
        WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
        boolean isWifiEnabled = wifiManager != null && wifiManager.isWifiEnabled();

Location availability

User with location disabled

It helps to know when the location is disabled and why this is so. We have observed that the incidents of enabling and disabling location services at the device level are higher on Android as compared to iOS. Detecting location services or permission changes on the device makes it possible to differentiate between the user disabling location and patchy GPS connectivity.

For example for apps for work like delivery management riders enabling or disabling location services directly impacts the customer’s ability to track the order. Knowing the reason for location unavailability solves two problems. Firstly the customer can be notified about the status while tracking the order. Secondly data about rider behavior can lead to a higher quality and reliability of service over time.

<receiver android:name="com.test.app.LocationSettingsChangedReceiver">
        <action android:name="android.location.PROVIDERS_CHANGED"/>
        <category android:name="android.intent.category.DEFAULT"/>
public class LocationSettingsChangedReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        // Device's location services status
        int locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
        boolean isLocationEnabled = locationMode != Settings.Secure.LOCATION_MODE_OFF;

        // Device's location permission status
        boolean isPermissionAvailable = true;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            isPermissionAvailable = context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED;

Device switched off/on

User with device switched off

It helps to know when the device is switched off. A switched off device would lead to disconnected network and unavailable location. Accurate detection of device being powered off or restarted is useful to recover location-based services in the app when the device is back on. Journaling the event helps inform team members interpreting the events in the life of the user.

<receiver android:name="com.test.app.PowerStatusChangedReceiver">
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.ACTION_SHUTDOWN" />
        <action android:name="android.intent.action.QUICKBOOT_POWEROFF" />
public class PowerStatusChangedReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            // Handle device powered on    

        } else if (intent.getAction().equals("android.intent.action.ACTION_SHUTDOWN")) {
            // Handle device powered down

        } else if (intent.getAction().equals("android.intent.action.QUICKBOOT_POWEROFF")) {
            // Handle device restarted

Device date/time

Accurate time stamps are critical in the world of location tracking. In our experience it is vital to solving for true time on Android. Often the clock on low-end Android devices goes out of sync. Besides users keep changing device times to hack their access to time-restricted games like Candy Crush. Journaling device health events to detect these changes help in maintaining the sanctity of timestamps in the location stack.

<receiver android:name="com.test.app.DeviceTimeChangedReceiver">
        <action android:name="android.intent.action.LOCALE_CHANGED"/>
        <action android:name="android.intent.action.TIMEZONE_CHANGED"/>
        <action android:name="android.intent.action.DATE_CHANGED"/>
public class DeviceTimeChangedReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.LOCALE_CHANGED")) {
            // Handle device locale changed

        } else if (intent.getAction().equals("android.intent.action.TIMEZONE_CHANGED")) {
            // Handle device timezone changed

        } else if (intent.getAction().equals("android.intent.action.DATE_CHANGED")) {
            // Handle device date changed

These are only a few basic device health events to keep you sane in the world of location tracking. Once you start using these the next set of questions will show up about inferring the happenings in the life of your users. In order to answer these questions device health events serve as important building blocks. We’ve got some awesome things coming up on our roadmap to bring more visibility into the user’s world. You would be able to use them to achieve better product experiences and business efficiencies.

API access to device health data

Device health eventsAccess in-appAccess via  User APIAccess via Events
Device’s Battery StatusGet user’s last updated batteryGet battery status updates via webhooks & Slack alerts
Device’s Network StatusGet user’s network statusGet user’s network connection statusGet network settings changes via webhooks & Slack alerts
Location Settings StatusGet user’s location settings statusGet user’s location settings statusGet location settings changes via webhooks & Slack alerts

Check out our SDK  and API documentation for detailed references.

Try it out

Looking to build live location features in your app? We can help. Get started now and try HyperTrack