Saturday 22 July 2017

Detecting mock locations on Android


Ever struggled with users mocking locations in your Android app? Mock location apps have gained popularity amongst app users on the back of Pokemon GO and an increasing number of location-aware apps. A large number of users have discovered the power of mock location apps in order to fake their locations and game the system. Ironically, mock location apps were created by developers as a tool to test location features. What started off as a solution for app developers has now become a widespread problem for them. We ended up creating a monster!


Our friends at on-demand delivery company Runnr brought this problem to our attention when certain users were faking locations to game the system. So we built a feature to resolve this.

Detecting mock locations

On Android 17 (JellyBean MR1) and below, mock locations are detected using Settings.Secure. The app can detect that users have enabled ALLOW_MOCK_LOCATION but has no easy way to determine whether locations received are mock or real.

Solution: The general pattern with mock locations is that bearing, speed, accuracy, altitude and time interval (between consecutive data points) are hard-coded values. The HyperTrack API server detects these patterns in order to discards such locations.
On Android 18 (JellyBean MR2) and above, mock locations are detected using Location.isFromMockProvider() for each location. The app can detect that the location came from a mock provider when the API returns true.
Solution: The HyperTrack SDK filters out mock locations on the device in order to prevent them from reaching the HyperTrack API server.

/**
* For Build.VERSION.SDK_INT < 18 i.e. JELLY_BEAN_MR2
* Check if MockLocation setting is enabled or not
*
* @param context Pass Context object as parameter
* @return Returns a boolean indicating if MockLocation is enabled
*/
public static Boolean isMockLocationEnabled(Context context) {
return !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
}
/**
* For Build.VERSION.SDK_INT >= 18 i.e. JELLY_BEAN_MR2
* Check if the location recorded is a mocked location or not
*
* @param location Pass Location object received from the OS's onLocationChanged() callback
* @return Returns a boolean indicating if the received location is mocked
*/
public static boolean isMockLocation(Location location) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && location != null && location.isFromMockProvider();
}

HyperTrack removes Mock Locations by default. Developers may enable them using HyperTrack.enableMockLocations(boolean) for testing.

Mock location apps insufficient for testing HyperTrack

In essence, mock location apps provide a continuous stream of locations (latlongs). The HyperTrack SDK generates more than that. Location data is accompanied with activity data. Location streams are organized as a collection of activities in the life of the user. Read more about it in our previous blog on the pitfalls of using location streams. This makes mock location apps insufficient for testing the full power of HyperTrack features.

Introducing HyperTrack.startMockTracking()


What Next?

Detecting Mock Locations and removing them was just the start. Here is a short summary of what we plan to do next to make this more useful:
  • For devices with Android 18 & above, add “Mock Location detected” event for a user to receive Slack alerts for unexpected events.
  • For devices with Android 17 & below, add “Mock Location enabled” warning to a user’s Placeline on the dashboard and widgets.
Let us know what more you would like to see from HyperTrack with regard to detecting mock locations. In case you haven’t started yet, visit www.hypertrack.com now to plug the SDK into your app. It takes a few minutes to start building your location features, now with the promise of detecting and removing mock locations with no extra lines of code.

No comments:

Post a Comment