GEMINI LABJP
SPARK — Gemini 3.7 Flash became the engine behind Gemini Spark on August 13. Choosing round-trip speed over reasoning depth for agent work is a useful signal when picking your own modelAGENT — Spark carries out multi-step tasks autonomously once granted permission, handling things like booking appointments and filling forms rather than answering one command at a timeASSISTANT — Fourteen days until Gemini replaces Google Assistant on September 4. Once a device migrates there is no going back, though cars with Google Built-in keep Assistant for nowEDUCATION — Since August 10, Gemini in Classroom is available to K-12 and higher-education students of any age, provided their administrator has granted accessSCALE — The Gemini app now generates 150 million images a day. The interesting part is less the volume than how that sustained load is absorbed in practiceMODELS — The split has settled: Gemini 3.1 Pro for deep reasoning, the Flash line for production work where speed and cost matter. Running the same job through both makes the gap concreteSPARK — Gemini 3.7 Flash became the engine behind Gemini Spark on August 13. Choosing round-trip speed over reasoning depth for agent work is a useful signal when picking your own modelAGENT — Spark carries out multi-step tasks autonomously once granted permission, handling things like booking appointments and filling forms rather than answering one command at a timeASSISTANT — Fourteen days until Gemini replaces Google Assistant on September 4. Once a device migrates there is no going back, though cars with Google Built-in keep Assistant for nowEDUCATION — Since August 10, Gemini in Classroom is available to K-12 and higher-education students of any age, provided their administrator has granted accessSCALE — The Gemini app now generates 150 million images a day. The interesting part is less the volume than how that sustained load is absorbed in practiceMODELS — The split has settled: Gemini 3.1 Pro for deep reasoning, the Flash line for production work where speed and cost matter. Running the same job through both makes the gap concrete
Articles/Dev Tools
Dev Tools/2026-08-21Beginner

How Many Assistant-Dependent Lines Are Still in Your App?

On September 4th, Google Assistant on Android begins its replacement by Gemini. Here is how to grep your own project for every entry point an assistant can open, and how to turn that list into utterances you can actually test on a device.

Gemini79Android12App ActionsIndie Development14Migration3

The oldest app I still maintain shipped in 2014. I opened its AndroidManifest.xml last week for an unrelated build fix and found a <capability> tag I have no memory of writing.

It was there so the app could be opened by voice. And if I do not remember writing it, I certainly do not remember testing it.

Starting September 4th, Google Assistant on Android is progressively replaced by Gemini. I cannot predict what each of those entry points will do afterwards. What I can do is find out where they are while the current behaviour still exists.

Counting is possible even when predicting is not. grep turns out to be enough for the counting part.

What changes on September 4th, and what does not

The scope first.

SurfaceAfter September 4th
Android phones and tabletsProgressively replaced by Gemini
Wear OS smartwatchesProgressively replaced by Gemini
Assistant-enabled headphonesProgressively replaced by Gemini
Android Auto projected from a phoneProgressively replaced by Gemini
Cars with Google built-inAssistant continues

The rollout happens in stages, and once a device has switched, there is no option to move it back to the old Assistant.

That last part is what makes this different from a normal platform change. Usually "wait until it breaks, then fix it" is a reasonable strategy: you can see the breakage, and you can roll back. Here you cannot roll back. Once your own device flips, the previous behaviour is no longer observable to you.

Which is exactly why the list of places worth checking should exist before the flip, not after.

Translate "assistant integration" into strings you can search for

The phrase "assistant integration" is not greppable. It has to be reduced to text that actually appears in files.

Entry pointWhat to search forWhere it usually lives
App Actions capability<capabilityres/xml/shortcuts.xml
ASSIST intentandroid.intent.action.ASSIST / ACTION_ASSISTManifest, activity code
Voice interactionVoiceInteraction / VOICE_COMMANDManifest, service code
Leftovers from actions.xmlNames in the actions.intent.XXX formUnder res/xml/
Static shortcuts<shortcut / android:shortcutIdshortcuts.xml, manifest
Dynamic shortcutsShortcutManager class namesKotlin / Java code
Auto-verified app linksandroid:autoVerifyManifest

Shortcuts and app links are not voice-only mechanisms, and you may well decide they are out of scope. Include them anyway for now: they are routes an assistant can use to open your app, and ruling them out is something to do after looking, not before.

grep is enough — a script that produces a ledger

The table above becomes the script. Point it at a project root and it prints a count per entry point and writes a CSV ledger.

#!/usr/bin/env bash
# assist-inventory.sh — find every entry point an assistant could open, and log it
# Usage: ./assist-inventory.sh <android-project-root> [output.csv]
set -u
ROOT="${1:-.}"
OUT="${2:-assist-inventory.csv}"
SEEN=$(mktemp)
 
printf 'surface,file,line,snippet,checked_on_device\n' > "$OUT"
 
# Match the most specific entry points first; a line already logged is skipped
while IFS='|' read -r label pattern; do
  [ -z "$label" ] && continue
  found=$(grep -rnE --include='*.xml' --include='*.kt' --include='*.java' \
            --exclude-dir=build --exclude-dir='.git' -- "$pattern" "$ROOT" 2>/dev/null)
  n=0
  while IFS= read -r hit; do
    [ -z "$hit" ] && continue
    file=${hit%%:*}; rest=${hit#*:}; num=${rest%%:*}; snip=${rest#*:}
    key="$file:$num"
    grep -qxF "$key" "$SEEN" && continue
    printf '%s\n' "$key" >> "$SEEN"
    snip=$(printf '%s' "$snip" | tr -d '\r' | sed 's/^[[:space:]]*//; s/"/""/g' | cut -c1-80)
    printf '%s,%s,%s,"%s",\n' "$label" "$file" "$num" "$snip" >> "$OUT"
    n=$((n + 1))
  done <<EOF
$found
EOF
  printf '%-26s %s\n' "$label" "$n"
done <<'SURFACES'
App Actions capability|<capability[ >]
ASSIST intent|android\.intent\.action\.ASSIST|ACTION_ASSIST
Voice interaction|VoiceInteraction|android\.intent\.action\.VOICE_COMMAND
actions.xml leftovers|actions\.intent\.[A-Z_]+
Static shortcut|<shortcut |android:shortcutId|android\.app\.shortcuts
Dynamic shortcut|ShortcutManager|pushDynamicShortcut|ShortcutManagerCompat
Auto-verified app link|android:autoVerify="true"
SURFACES
 
rm -f "$SEEN"
echo "---"
echo "Ledger: $OUT ($(( $(grep -c . "$OUT") - 1 )) rows)"

Three things happen here. Each row of the table is read as label|regex, grep -rnE looks for it, and only a file:line pair that has not been logged yet gets appended.

Run against a small project containing one capability, one ASSIST intent and one static shortcut, the output looks like this:

App Actions capability     1
ASSIST intent              1
Voice interaction          0
actions.xml leftovers      0
Static shortcut            2
Dynamic shortcut           0
Auto-verified app link     0
---
Ledger: assist-inventory.csv (4 rows)

And the CSV:

surface,file,line,snippet,checked_on_device
App Actions capability,./app/src/main/res/xml/shortcuts.xml,2,"<capability android:name=""actions.intent.GET_THING"">",
ASSIST intent,./app/src/main/AndroidManifest.xml,12,"<action android:name=""android.intent.action.ASSIST"" />",
Static shortcut,./app/src/main/res/xml/shortcuts.xml,5,"<shortcut android:shortcutId=""daily"" ...",
Static shortcut,./app/src/main/AndroidManifest.xml,8,"<meta-data android:name=""android.app.shortcuts"" ...",

The trailing checked_on_device column is deliberately empty. It is where you write the date you verified that row on a real device.

Two things only running it revealed

My first version was not shaped like this. Running it produced two corrections.

The first was a false positive. Written as <shortcut, the static-shortcut pattern also matched the root element <shortcuts> on line 1 of the file. One character apart, and invisible when you read the pattern rather than run it. Adding a trailing space — <shortcut — removed it.

The second was double counting. The single line <capability android:name="actions.intent.GET_THING"> matches both <capability and actions.intent.. When one line appears twice under two labels, the totals read higher than reality.

Hence the file:line bookkeeping that skips a line the second time around. But that choice has a consequence: match order now determines the label. Whichever pattern hits first owns the line.

So the list is ordered from specific to general, with <capability deliberately ahead of actions.intent.. In the run above, "actions.xml leftovers" shows 0 not because nothing matched, but because that one line was already counted as a capability.

When you run this on your own project, treat the ordering as something to question. Rearranging it moves the numbers.

Turn the ledger into utterances you can say out loud

A list of file paths does not tell you what to say to the device. That part is worth handing to Gemini: read the unchecked rows, produce one test utterance per row in both languages.

First, building the prompt from the CSV:

import csv
 
def load_unchecked(path):
    with open(path, newline="", encoding="utf-8") as f:
        return [r for r in csv.DictReader(f) if not r["checked_on_device"]]
 
def build_prompt(rows, app_name):
    lines = [
        f"{i + 1}. [{r['surface']}] {r['file']}:{r['line']} - {r['snippet']}"
        for i, r in enumerate(rows)
    ]
    return (
        f"Below are the entry points in the Android app \"{app_name}\" "
        "that a voice assistant could use to open it.\n"
        "For each one, write a single spoken phrase, in English and in Japanese, "
        "that I can say to a device to verify the behaviour.\n"
        "Always include the app name, and keep it to something a person "
        "would realistically say.\n\n"
        + "\n".join(lines)
    )

Then the call itself. Since the result feeds the next step rather than my eyes, the response is constrained by a schema:

import os
from google import genai
from pydantic import BaseModel
 
class Utterance(BaseModel):
    surface: str
    file: str
    en: str
    ja: str
 
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
 
rows = load_unchecked("assist-inventory.csv")
response = client.models.generate_content(
    model="gemini-3.7-flash",
    contents=build_prompt(rows, "Wallpaper"),
    config={
        "response_mime_type": "application/json",
        "response_schema": list[Utterance],
    },
)
 
for u in response.parsed:
    print(f"[{u.surface}] {u.file}\n  EN: {u.en}\n  JA: {u.ja}\n")

Passing list[Utterance] as the response_schema means the response comes back as a list of Utterance objects, with no JSON parsing of your own.

One note on what is missing: there is no temperature. The sampling parameters are deprecated now, and if the goal is a stable shape rather than a stable wording, pinning the schema does that job better than tuning a number ever did. It is an easy line to copy forward from older sample code without noticing.

Measuring how voice-driven launches change across the cutover is a separate exercise, and it has to start before the switch for the same reason. If the measurement side interests you, The Assistant replacement cannot be undone, so the baseline has to be taken now covers that ground.

What to decide in the two weeks left

If only one thing gets done, make it this: switch a single device to Gemini ahead of the rollout and start filling in the checked_on_device column.

You can move to Gemini on your own schedule from the Google app or from device settings, without waiting for September 4th. Switch one device, not all of them, or you lose your comparison. Say each utterance on that device, record whether the app opened, and the rows that did not open become your work list for September.

The counting takes about fifteen minutes today and becomes impossible once the device has flipped. That ordering is the whole point.

For what it is worth, I still have not verified the tag I wrote four years ago. If you are carrying similar leftovers, I hope this makes the first fifteen minutes of it easier.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-06-21
Finding Every Reference to the Image Preview Models Before They Stop on June 25
gemini-3.1-flash-image-preview and gemini-3-pro-image-preview stop on June 25. Here is a dependency audit for surfacing references buried in rarely-run branches and batches before the cutoff.
Dev Tools2026-07-18
I Was Handing Gemini Obfuscated Stack Traces — Until retrace Went In Front, the Diagnoses Were Confident and Wrong
Release stack traces come out of R8 with the names flattened. Feed one to Gemini as-is and the diagnosis arrives calm, well-written, and wrong. Put retrace in front, match the mapping by versionCode, and forbid confident answers when you cannot restore. Numbers from 42 reports.
Dev Tools2026-06-24
Folding a Local Gemma 4 into Daily Work — Practical Notes on the Ollama API and Response Speed
Taking a local Gemma 4 you can now run interactively and folding it into real work: how to hit Ollama's local API from a script, tricks to improve perceived response speed, and a two-tier fallback that automatically routes to the cloud Gemini API — code included.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →