aher.dev

Jarvis

A coach that calls.

Jarvis is the phone half of an accountability coach, and when a plan needs a conversation it rings like a real call and tells the coach what happened.

Android app. Version 0.5.0. Source not public.

Download APK (59 MB)Back to the blog

Ring pushRingingDeclinedAnswerNo answerIn callJoin failedover the lock screen20 s to joinends, reportednot a dodgeEvery outcome here is reported to the server.
The ring. Answer is the only way into a call. Declining and letting it ring out are both reported. A call that fails to connect within 20 seconds is reported too, and it never counts as a dodge.

Why

A reminder is easy to swipe away.

A notification costs nothing to dismiss, and a reminder read aloud is still a notification with a ringtone. Turnout studies found the same pattern. Scripted and robot calls did not move voters, and conversational calls did (Gerber and Green, 2000; Nickerson, 2007).

Jarvis is for someone who knows what they should be doing and keeps not starting. A coach server decides when to remind and when to call. The phone shows the reminder, rings for the important ones and reports back. The app writes no text of its own. Every line on screen comes from the server.

The words live on the server, and each rule behind them comes from a study of delay. The phone exists to make these rules possible.

Ask what makes the task unpleasant.

A meta-analysis of 691 correlations found that procrastination is predicted best by an unpleasant task, a deadline that is far away, low self-efficacy and impulsiveness, while anxiety is weak (Steel, 2007). The coach asks what makes the task unpleasant and what the first step is.

Lower the threat of starting.

Putting a task off is short-term mood repair, and the cost lands on the future self (Sirois and Pychyl, 2013). A call never opens by asking why the task is not done.

End with a plan.

Plans in the form “when X, I will do Y at Z” had an effect of d = 0.65 across 94 tests (Gollwitzer and Sheeran, 2006). Every call ends with a spoken when, where and what.

Say the plan out loud, with someone.

Mental contrasting with implementation intentions run live scored g = 0.47, against 0.28 on paper (Wang, Wang and Gai, 2021). That is the case for a voice call over a worksheet.

Check the yes.

A spoken yes is a claim (Feeley and colleagues, 2012). The phone sends the coach what it can see, so a yes can be checked later.

Forgive the miss.

Forgiving yourself after a miss reduces later procrastination (Wohl, Pychyl and Bennett, 2010). After a miss the coach says “that happened; what is the next small step”.

The ring

Only Answer starts a call.

A ring push arrives with high priority. It starts a foreground service of the phone-call type and shows a full-screen ring over the lock screen, with the ringtone on the ringtone channel. Nothing answers by itself.

Decline is reported as declined, and silence as a timeout. Answer joins a voice call with the microphone and gives it 20 seconds to connect. A failed join is reported as join failed, and it never counts as a dodge. Each push rings once. A ring with voice turned off rings the same way, and Answer opens the item with Done and Time.

The push

Every push takes the same path.

The app checks each push before it does anything. A malformed push is ignored. A push it has already seen is a repeat. A push past its expiry is acknowledged as expired and never shown. Everything else is acknowledged to the server within 3 seconds, then shown as a notification with Done and Time, or cancelled.

ReceivedCheckedAcked within 3 sNotification shownTap saved, then sentMalformedignoredRepeatseen beforeExpiredacked, not shownCancelledOne answer per push,saved before it is sent.
The push path. Malformed, repeated and expired pushes leave at the check, and none of them is shown. A valid push is acknowledged within 3 seconds, then shown. A tap on Done or Time is saved before it is sent.

The outbox

A tap made with no signal still arrives.

Each push takes one answer. The answer is written to an outbox on the phone first and sent second. If the server errors or there is no network, the app tries again after 1 minute, then 5, then 15. A request the server rejects for any other reason, such as a phone that is no longer paired, is dropped, because retrying would not fix it.

The outbox lives in a database on the phone, so it survives a reboot. A background worker also flushes it every 15 minutes and after any failure.

Tap DoneOutboxServersaved before sendingtry 1try 2try 3try 41 min5 min15 minofflineonlineThe saved row survives a reboot.
The outbox. The tap is saved first. The first send and two retries fail while the phone is offline. The retry 15 minutes later goes through, and the saved row clears. Gaps are not drawn to scale.

The senses

The coach knows the situation before it calls.

Every 15 minutes the phone sends one heartbeat with location, app usage and the sleep window. Sleep comes from Health Connect, or from the first unlock as a last resort. That is how the coach checks a spoken yes.

Location follows motion. The phone takes a fix every 2 minutes while moving, every 10 while still and every 15 at night. Heartbeats survive reboots and Android’s Doze mode, and they queue while the server is unreachable. Each one shows up as a line on a Senses screen. A Permissions screen has one card for each thing a ring depends on, and a privacy screen lists what is sent.

What I learned

Four rules the phone side taught me.

A ring with voice off has to clear itself.

It rings like any other, and Answer opens the item with Done and Time. If it does not clear, it blocks the next real ring.

A service has to finish starting before it stops.

Every stop path waits until the call service has finished moving to the foreground.

Save first, send second.

Writing every tap to the outbox before the network call is why a tap survives a dead network.

The ring lives on the phone and the words live on the server.

That split keeps the app small, and the app cannot say anything the coach did not decide.

Try it

Install the test build.

Kotlin, Firebase Cloud Messaging data pushes, a call-style notification, foreground services for the call, location and the microphone, Room, WorkManager, Health Connect and a WebRTC call client. It pairs once with a coach server by a one-time code or link, keeps its device secret in encrypted storage and registers again after a reboot or an update.

Download APK (59 MB)

Test-signed build. Android 9 or later. Download the file and install it from the file; Android will warn about an unknown source.

Without a coach server to pair with, the app only shows its pairing screen.

  • Kotlin
  • Firebase Cloud Messaging
  • Room
  • WorkManager
  • Health Connect
  • WebRTC

Source not public.

Sources

  1. Steel, 2007. Meta-analysis of procrastination.
  2. Sirois and Pychyl, 2013. Procrastination and short-term mood repair.
  3. Gollwitzer and Sheeran, 2006. Implementation intentions, 94 tests.
  4. Wang, Wang and Gai, 2021. Mental contrasting with implementation intentions.
  5. Gerber and Green, 2000. Canvassing, phone calls and mail on voter turnout.
  6. Nickerson, 2007. Volunteer and professional turnout calls.
  7. Feeley and colleagues, 2012.
  8. Wohl, Pychyl and Bennett, 2010. Self-forgiveness and procrastination.

Back to the blogAll projects