androidengineers.Book a session

Recovery, recipe context and future tools

Session recovery and the boundary before tools

article35–50 min

Recover the recipe first

PocketCook makes recipe progress durable and conversations disposable. LocalProgress uses SharedPreferences for the current recipe step. Ingredient checks and transcripts are memory-only. Process recreation returns to the library; selecting a recipe restores its saved position. Rotation retains the ViewModel, while backgrounding explicitly ends voice and clears the key.

This is a small, inspectable policy. It avoids secretly restarting a microphone after a process is recreated. It also means the learner must re-enter a key after leaving the app. That inconvenience is intentional in this debug sample.

// CookViewModel.kt — background policy
fun background() {
    live.end("Voice stopped while the app was away. Tap to start again.")
    key = ""
}

MainActivity.onStop invokes this unless a configuration change is in progress. Trace both paths: a rotation should retain screen state; pressing Home should stop voice. A ViewModel alone does not decide that policy—the Activity reports lifecycle changes to it.

Retry is a fresh conversation

The controller increments a generation when ending a session. Callbacks from old sockets compare their captured generation before mutating state. Start opens a fresh socket with the selected recipe/current step. It does not implement provider session resumption or guarantee continuation of the old conversation.

The baseline cancels after setup timeout, explicit end, local session limit, server expiry, protocol rejection or transport failure. Errors preserve a bounded transcript for inspection when the controller fails; normal end resets voice state. The user chooses when to retry. There is no automatic reconnect loop.

Write a timeline with sockets A and B. End A, start B, then deliver A's setupComplete. Without a generation guard, A could create audio resources inside B's session. oldSocketCannotReopenNewSession tests that exact ordering. Another test simulates network failure and then starts again; it does not physically switch a phone's network.

Context is data; speech is not an action

When the learner presses Next, CookViewModel.step clamps the index, persists it, updates UI state and tells the live session the new position. The server receives text context with turnComplete=false, so this update is not treated as a request for an immediate spoken turn by the sample.

// Recipes.kt — the local bounds rule
fun boundedStep(requested: Int, count: Int): Int =
    requested.coerceIn(0, (count - 1).coerceAtLeast(0))

The app remains the authority for step state. Asking “what next?” can produce spoken guidance; it does not advance the screen. Current tools are not implemented, despite this article's preserved URL. The course now teaches the boundary accurately before asking you to extend it.

Design a future tool as a constrained command

A later navigation tool would need an allowlisted name, typed arguments, range validation and an execution result. A timer would also need a bounded duration and a stable call identity so a duplicate request cannot create two timers. Those are local application rules, not prompt instructions.

For the design exercise, specify what happens for an unknown tool, missing index, negative duration, repeated call ID and cancellation. Keep it a paper contract: do not claim the baseline has a tool executor. If a response says an operation succeeded but the app never performed it, the UI must not display a fabricated result.

Production authentication is another milestone

A release client should not contain the provider's long-lived key. The planned token service must authenticate requests, constrain token issuance, limit abuse and handle expiry. Google describes the ephemeral-token flow in its official guide. The baseline has no server directory implementing that flow; release builds keep voice disabled.

Do not fix this by putting a key in local.properties and compiling it into BuildConfig. That changes where the developer types it, not what an installed client can reveal.

Observable recovery checks

Advance to step three, background the app, return, and confirm voice is idle while progress remains. Reconnect explicitly. Repeat with a network disconnect and record the actual delay until the app notices; do not impose an invented universal timing guarantee. Finally rotate during an offline cooking step and verify the index. Attach separate evidence for simulated callbacks, real lifecycle behavior and actual network loss.

Course study guide · Hands-on codelab · Pinned Android source

YOUR LEARNING JOURNEY

0 of 16 available lessons completed

Progress saved in this browser. No account needed.
Session recovery and the boundary before tools | Gemini Live for Android with PocketCook | Android Engineers