Learn through PocketCards, the runnable flashcard app in Android + AI Cookbook. Open the hands-on codelab · Browse the pinned source.
Use a known source revision
Follow the PocketCards codelab alongside this lesson. It uses a completed runnable sample as the baseline, then asks you to make and test a focused improvement. There is no separate starter branch. Pinning the checkout makes file names and code snippets reproducible as the cookbook evolves.
git clone https://github.com/AndroidEngineers/android-ai-cookbook.git
cd android-ai-cookbook
git switch -c learning/pocketcards c527701
cd ai-fundamentals
./gradlew :app:assembleDebug :app:testDebugUnitTest :app:lintDebug
On Windows use gradlew.bat. Open ai-fundamentals in Android Studio, not the repository root: each topic owns its own Gradle project. Use JDK 17 and install Android SDK 36 and Build Tools 36.0.0. Set the SDK location locally. Do not commit local.properties or Firebase configuration.
Establish a no-cloud baseline
Run the app, study the handwritten sample and create a manual card. If these fail, debug the Android setup before adding a network service. Unit tests use injected fakes and need no Firebase project. This keeps build problems separate from credentials, attestation and quota problems.
Connect the actual boundary
Register com.androidengineers.pocketcards in your Firebase project, enable Firebase AI Logic for the Gemini Developer API backend, and put the downloaded configuration in app/google-services.json. Rebuild: the Google Services plugin applies only when that file exists. Adding it without rebuilding cannot change the installed APK.
The debug source set installs the App Check debug provider. Obtain its token from local Logcat and register it for this Android app in Firebase App Check. Keep the token outside Git and recordings. A 403 attestation failure means you must investigate registration, project/package matching and token propagation; it is not proof that the notes are invalid.
Read the adapter, then test it
FirebaseCardGenerator defines a schema, selects the model through BuildConfig.MODEL_NAME and calls generateContent inside a timeout. The response is parsed through CardValidation before the ViewModel accepts it. Read that file in full and point to each boundary before pressing Generate.
Use the same public passage on your first run: photosynthesis converts light energy into chemical energy; plants use carbon dioxide and water to produce glucose and oxygen; chlorophyll absorbs light; the process occurs in chloroplasts; glucose supports plant growth. Review each generated answer against those facts. Save only after review, reopen the deck and finish every card.
Diagnose by layer
A missing SDK is a build problem. A disabled generation button can indicate missing configuration or fewer than 40 characters. Attestation failure is a project/device verification problem. Valid JSON with an unsupported answer is a quality problem. A crash on Got it is an application-state problem. These demand different fixes; repeatedly rewriting the prompt will not repair all of them.
Checkpoint: Provide a reproducible checkout command, a successful manual run, one live generation and a recorded failure/retry. Include a screenshot of the app, never a console screenshot containing tokens. Link your evidence to the exact code revision.
Explain each boundary in the response path
The adapter ends with this actual expression:
return CardValidation.parse(
response.text ?: error("No cards were returned. Try different notes.")
)
response.text is nullable because a request does not guarantee usable text. The Elvis operator selects the failure path when there is no text. parse then turns the textual response into application data and applies the validation rules. Only accepted cards are returned to the ViewModel. A network success therefore does not necessarily become a successful draft.
Trace three outcomes before running them:
- No response text: parsing does not run; the request fails with a recoverable error.
- Malformed or invalid cards: parsing/validation fails; the app must not save a partial deck automatically.
- Structurally valid but invented answer: parsing can succeed; review and evaluation must catch the quality failure.
The codelab changes one precise validation behavior: repeated whitespace must not make equivalent questions appear distinct. Write the regression test first. If it already passes on an unmodified baseline, check the revision and confirm that you actually created whitespace-equivalent questions. A green test that never exercised the defect is weak evidence.
Completion checkpoint: Demonstrate manual use, actual cloud generation, explicit review/save, reopen, and final-card completion. Then explain one failed request and one failed validation without changing unrelated layers. Link the test evidence to your commit, not simply to the upstream main branch.