When we started building an Android screen-time app that gates access to distracting apps on a step count, the first engineering question was: how do we count the steps? There are basically two paths — the hardware step counter sensor, or GPS-based distance tracking. We picked the hardware sensor. This is what we found.
The two options, in one paragraph
The hardware step counter is a tiny chip on the phone that counts steps on its own, in a low-power hardware block, and surfaces a running total to the OS. It does not need network access, does not need location permission, and is accurate to within a few percent for normal walking. GPS-based distance tracking reads your location at high frequency, calls into the system location service, requires the fine-location permission, and is great if you are a runner who wants a route on a map.
Battery
This is the headline. The hardware step counter is essentially free. On a Pixel 7 in a 24-hour pocket test with the screen mostly off, the step counter contributed under 1% battery. That is the reason it is allowed to keep counting when Doze mode kicks in. GPS, even with adaptive batching, wants the radio awake for line-of-sight to the satellites. A session of "is the user walking" polling at 1 Hz can drain 5-10% per hour, depending on sky view. For an app that is allowed to keep running in the background to enforce a daily step goal, that is a deal-breaker.
Privacy
The hardware step counter produces a single integer — the total step count since the last reboot. It does not know where you walked, how fast, or in what direction. It does not require any permission, because there is no personal data inside the count. GPS produces a stream of lat/long pairs at sub-second resolution. Even if you trust the app, you are trusting every library it depends on, every ad SDK it might load later, and the OS-level cache that holds the last fix. We did not want that on the device for an app whose entire reason to exist is helping people use their phone less.
Accuracy
For "is the user walking", the hardware sensor is good enough. In a 30-day test, the sensor was within 4% of a manual count during a normal commute, and within 8% during mixed activities (car + walking + stairs). GPS is more accurate for distance, less accurate for step count, because a satellite fix can drift indoors. For our use case — gating "is the user moving on foot" — both are overkill, but the hardware sensor is the cheaper, simpler, more private option.
The system API in 30 lines
If you are an Android developer, the hardware step counter is one sensor registration:
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val stepCounter = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
sensorManager.registerListener(object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
val totalSteps = event.values[0].toInt()
// store, render, gate
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
}, stepCounter, SensorManager.SENSOR_DELAY_NORMAL)
TYPE_STEP_COUNTER is a cumulative count since the last reboot. TYPE_STEP_DETECTOR is a per-step event. The first is what you want for a daily budget, the second is what you want for a pedometer UI. We use both.
What we gave up
- We cannot show a route on a map. We never wanted to.
- We cannot distinguish "walking" from "running" from "cycling" without a second sensor. For our use case (a step count), this is fine.
- We cannot count steps taken before the user installs the app. The counter starts at install time.
What we got
- A background-friendly step source that does not ask for location.
- A permission-light install flow that is friendly to Android 13/14 restrictions.
- A privacy story that fits on a one-line privacy page.
For a screen-time app, the choice was obvious. If you are building a fitness tracker, the calculus is different and GPS may be the right call.
The full code and a longer write-up are in StepShield Pro on Google Play. The privacy page is at nexusdriftstudio-a11y.github.io/steplockprivacy.html.
Top comments (0)