In the quest to create a seamless communication tool for my mother, who resides in a village while the rest of our family is scattered across urban landscapes, I embarked on developing an Android application named CareVocal, internally referred to as CareBridge. The app is designed with simplicity in mind, featuring three prominent buttons: green for “feeling good,” yellow for “something hurts,” and red for “need help.” The functionality of the red button is paramount, and it is here that I encountered challenges that tested my coding skills and design principles.
What the red button is supposed to do
With a single tap on the red button, the app is programmed to execute three critical actions:
- The entry is saved and flagged for her doctor.
- A pre-filled SMS is generated, directed to her trusted contacts, complete with a fixed alert message and a timestamp. Notably, no location data is collected.
- The phone dialer opens with the local emergency number pre-typed.
This design ensures that she must still tap “send” and “call,” a deliberate choice to avoid automatic dialing and adhere to Google Play’s restrictions on background messaging. The app prepares everything, but a human touch is required to confirm the actions.
A guiding principle I established before writing any code was that the alert never waits on anything slow. This includes transcription, network delays, or microphone input, as the user may be in a vulnerable state—dizzy, frightened, or both.
Bug 1: the dialer wins, the SMS vanishes
During initial testing on my own device, I tapped the red button, expecting the SMS to appear alongside the dialer. However, only the dialer surfaced, leaving the SMS draft absent. My initial code executed two intents back-to-back:
context.startActivity(smsIntent)
context.startActivity(dialIntent)
This approach assumed that Android would prioritize the first intent, but the operating system’s transition caused the first intent to be dropped entirely, resulting in only the dialer being displayed.
The “fix” that just moved the bug
Following standard advice, I introduced a delay between the two intents:
context.startActivity(smsIntent)
delay(500)
context.startActivity(dialIntent)
With real trusted contacts configured, I tested the red button again. The SMS drafted correctly, but this time, the dialer failed to open. The delay allowed the SMS app to take the foreground, blocking my app from launching the dialer due to Android’s restrictions on background apps. This led to another failure, demonstrating that no delay value could effectively bridge the two calls, as they were racing against different OS mechanisms.
The fix: one call, no gap
The core issue was not the delay itself but the existence of a gap. Android provides a method to launch multiple intents as a single operation:
context.startActivities(
listOfNotNull(
RedFlowIntents.sms(signal.recipientNumbers, message),
RedFlowIntents.dialEmergencyNumber(emergencyNumber),
).toTypedArray()
)
This method ensures that the last intent in the array appears on top, allowing the dialer to be visible while the SMS draft remains accessible beneath it. The use of listOfNotNull means that if no trusted contacts are configured, the SMS intent is simply omitted, allowing the dialer to open without error messages. I confirmed this functionality on the device, ensuring that zero contacts yield only the dialer, while multiple contacts produce both the SMS draft and the dialer, without any racing issues.
The third failure, which wasn’t a code bug
In addition to the alert features, the red button was designed to record her voice, enabling her doctor to hear her words later. Initially, the recording began immediately upon tapping the button, lasting fifteen seconds. However, usability testing revealed a significant flaw: if she tapped the red button while feeling dizzy, the subsequent screens could distract her for several moments, causing the recording window to expire before she returned to the app.
To address this, I decoupled the recording feature from the alert process. Now, the first tap solely executes the essential actions—saving the entry, raising the alert, and pre-filling the dialer. Recording commences only upon a second, deliberate tap on the red button, ensuring that the alert is independent of the recording process. This design guarantees that even without microphone permissions, the alert functions effectively, as it does not rely on capturing her voice.
What I’d tell another builder
- Test the failure path on a real device, with real data. Both bugs were invisible in setups that did not reflect actual usage scenarios.
- If your fix involves adding a delay, consider what processes are competing. In my case, the delay merely shifted which action was prioritized.
- Document your never-events before coding. My guiding principles included never auto-dialing, never auto-messaging, never collecting location data, and ensuring alerts do not depend on transcription.
- Usability issues often escape unit tests. A feature can function correctly yet still fail to serve its intended purpose.
CareVocal stands as my entry for Shipaton 2026, crafted for a genuine patient—my mother—who inspired the very existence of the red button. The app is designed solely for logging and communication, without any diagnostic capabilities or decision-making authority on her behalf.