The problem
A rideshare driver has roughly fifteen seconds to accept a trip. In that window they are asked to judge a fare against fuel, depreciation, insurance, the dead miles to the pickup, and whether the drop-off strands them somewhere with no return fare. Nobody can do that arithmetic in fifteen seconds, so most drivers use instinct — and lose a meaningful share of their income to trips that never made money.
Uberfi answers one question, fast enough to be useful: keep this trip, or reject it?
How it works
An Android Accessibility Service watches for trip requests and classifies the text on screen — fare, distance, duration, rating, status — using anchored regular expressions rather than naive substring checks, so “Premium” and “15 minutes left” no longer register as a fare or a distance. The service is scoped to the Uber packages and re-verifies that the active window still belongs to Uber before it reads a single node.
Those readings stream into a pure-TypeScript ROI engine, which combines them with the driver’s vehicle profile — engine type, efficiency, insurance, depreciation per mile, and the local fuel or charging price — to produce a net trip value and an effective hourly rate. A Kotlin overlay then draws a floating verdict banner on top of the Uber app.
Net trip value = upfront fare − (pickup miles + trip miles) × cost per mile, with a penalty applied when the drop-off lands in a low-demand zone.
Decisions worth naming
- The banner must never be tappable. The overlay window is added with
FLAG_NOT_TOUCHABLE, so every touch passes through to the app underneath. A utility that can intercept a driver’s Accept button is not a utility. - Read as little as possible. A package allow-list plus a second guard on the active window means nothing outside the Uber app is ever inspected — the narrowest reasonable surface for a service with this permission.
- The maths is a pure function. The ROI engine has no React and no side effects, so the part of the app that decides whether a driver earns money can be tested in isolation.
- Under three seconds, end to end. Screen read, calculation and render have to complete well inside the request window, which rules out live model inference on the critical path — zone scores are pre-computed and cached instead.
- Ship the calculator before the overlay. A manual-input version gathers real vehicle data and calibrates the cost model with no risk to anyone’s driver account, before the accessibility permission is ever requested.
What it runs on
React Native and TypeScript on the client, with the accessibility service in Java and the overlay in Kotlin. The trip-stream detector assembles a live request from tagged screen readings and expires them after twenty seconds, so a stale fare can never be priced against a new trip.
Four screens sit behind the overlay: onboarding and vehicle profile, where a driver sets engine type, efficiency, insurance and depreciation; a trip analytics dashboard showing net earnings, effective hourly rate and a kept-versus-rejected history; the live overlay itself; and a positioning heatmap.

