On May 12, 2026, I was working in Antigravity when an email arrived from the Android team. Subject line: "The Android Show: Developer's Cut." I almost skipped it, but the opening line caught my attention.
"Android is transitioning from an operating system to an intelligence system."
OS to Intelligence System. I sat with that sentence for a moment. I've been building Android apps since 2014, and throughout that time, Android always meant "something the user directly controls." That premise just changed.
With a portfolio of wallpaper apps that have crossed 50 million total downloads, I couldn't treat this as something to deal with later. This is a record written the day after I actually touched the AppFunctions API.
What Android Transitioning to an Intelligence System Actually Means
At the core of this announcement is something Google is calling Gemini Intelligence — a new AI integration layer designed to let Android devices anticipate user needs so apps can deliver experiences at exactly the right moment.
Two integration paths are provided for developers:
Path 1: Task Automation (zero code changes) Gemini navigates the existing app UI on the user's behalf to complete tasks. Examples include building a grocery order or requesting a ride. No changes to your app code required.
Path 2: AppFunctions API (developer-controlled) Developers explicitly define app features as "tools" with natural language descriptions, publish them to the OS, and Gemini discovers and calls them at the right time.
What struck me was that Google's official blog used the phrase "in an MCP-like fashion" to describe AppFunctions. They're applying the Model Context Protocol concept — familiar to anyone working with AI coding tools — to the Android platform itself.
Two Integration Paths and the Indie Developer Reality
I found it more useful to ask "which path fits my app's values?" rather than "which path should I choose?"
Task Automation is the right fit when:
- Your app already uses standard Navigation Component with clear screen hierarchies
- Users repeat predictable patterns (e.g., always picks a wallpaper from the same category every morning)
- You need quick coverage without engineering investment
AppFunctions API is the right fit when:
- Your app has complex business logic that can't be replicated through screen navigation alone
- You want to connect abstract inputs ("I'm feeling calm today") to specific in-app actions
- You're making a long-term investment in AI ecosystem integration
For a wallpaper app, "have Gemini pick a wallpaper based on my mood" runs into Task Automation's ceiling quickly. Turning an abstract input like "calm" into a "filter by category" + "save to favorites" workflow requires exposing deliberate business logic. AppFunctions is the right tool here.
How AppFunctions Work — The "Named Tool" Model
AppFunctions are built around publishing app capabilities as tools with names and natural language descriptions. The OS discovers these tools and makes them available to agents like Gemini.
The mental model maps closely to defining tools in an MCP server: function name, parameters with types and descriptions, return values, and a human-readable explanation of what the tool does and when to use it.
KakaoTalk is mentioned in the developer blog as an Early Access Program participant, having published two AppFunctions: "send messages" and "initiate voice calls." Google also noted that 25 apps' use cases are already running locally on device. These early examples suggest a clear design direction — start with high-frequency, high-value actions.
AppFunction structure:
- id: unique identifier scoped to your package name
- description: natural language explanation Gemini uses to decide when to call this
- parameters: typed definitions with examples
- implementation: a Kotlin suspend fun
Of these, the quality of description and parameters has the most direct impact on how well Gemini uses your function.
Minimum AppFunctions Implementation in Kotlin
Based on the EAP alpha documentation and Android's established annotation-based API patterns (App Actions, Shortcuts), here's a working minimum implementation for a wallpaper app.
First, add the dependency to build.gradle.kts:
// build.gradle.kts (app module)
dependencies {
implementation("androidx.appfunctions:appfunctions:1.0.0-alpha01")
implementation("com.google.firebase:firebase-ai:25.0.0")
kapt("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha01")
}Define the AppFunction. For a wallpaper app, we expose "select and set a wallpaper by mood":
// WallpaperAppFunctions.kt
import androidx.appfunctions.AppFunction
import androidx.appfunctions.AppFunctionContext
import androidx.appfunctions.AppFunctionResult
@AppFunction(
id = "com.example.wallpaper.SET_WALLPAPER_BY_MOOD",
description = "Set device wallpaper based on user's current mood or preference. " +
"Supports moods like 'calm', 'energetic', 'nature', 'minimal', and 'seasonal'. " +
"Use this when the user wants to change their wallpaper based on how they feel.",
parameters = [
AppFunction.Parameter(
name = "mood",
description = "The mood or theme for wallpaper selection. " +
"Examples: calm, nature, minimal, energetic, space, warm, seasonal",
type = String::class
),
AppFunction.Parameter(
name = "setImmediately",
description = "Whether to apply the wallpaper right away (true) " +
"or open a preview screen first (false). Defaults to false.",
type = Boolean::class,
required = false
)
]
)
class SetWallpaperByMoodFunction(
private val wallpaperRepository: WallpaperRepository,
private val wallpaperManager: WallpaperManager
) : AppFunction {
override suspend fun execute(
context: AppFunctionContext,
parameters: Map<String, Any?>
): AppFunctionResult {
val mood = parameters["mood"] as? String
?: return AppFunctionResult.error("mood parameter is required")
val setImmediately = parameters["setImmediately"] as? Boolean ?: false
val wallpaper = wallpaperRepository.findByMood(mood)
?: return AppFunctionResult.error("No wallpaper found matching mood: $mood")
return if (setImmediately) {
wallpaperManager.setWallpaper(wallpaper.bitmap)
AppFunctionResult.success(
message = "Wallpaper set to \"${wallpaper.title}\" ($mood theme)",
data = mapOf("wallpaperId" to wallpaper.id, "title" to wallpaper.title)
)
} else {
AppFunctionResult.deepLink(
uri = "wallpaperapp://preview/${wallpaper.id}",
message = "Opening preview for \"${wallpaper.title}\""
)
}
}
}The most critical detail here is the description field. The phrase "Use this when the user wants to change their wallpaper based on how they feel" explicitly tells Gemini when to invoke this function. "Supports moods like 'calm', 'energetic'..." gives Gemini concrete vocabulary it can match against user intent. Writing this is the same exercise as writing good tool descriptions for an MCP server.
Register the AppFunction in AndroidManifest.xml:
<!-- AndroidManifest.xml -->
<application>
<meta-data
android:name="androidx.appfunctions.APP_FUNCTIONS"
android:resource="@xml/app_functions" />
</application><!-- res/xml/app_functions.xml -->
<app-functions>
<app-function
android:id="com.example.wallpaper.SET_WALLPAPER_BY_MOOD"
android:enabled="true"
android:allowedCallers="com.google.android.apps.assistant" />
</app-functions>The allowedCallers restriction ensures only the Gemini assistant can invoke this function — recommended during the EAP phase for security reasons.
Firebase AI Logic × Gemini 2.5 Pro for In-App AI Features
Separate from having Gemini operate your app via AppFunctions, you can also use Gemini inside your app to enhance the user experience. Firebase AI Logic makes this straightforward.
For a wallpaper app, this enables natural language interactions like "what time of day works best with this wallpaper?" or "suggest a category that matches today's weather."
// AIWallpaperAdvisor.kt
import com.google.firebase.ai.FirebaseAI
import com.google.firebase.ai.GenerativeModel
import com.google.firebase.ai.type.GenerationConfig
import com.google.firebase.ai.type.content
class AIWallpaperAdvisor {
private val model: GenerativeModel by lazy {
FirebaseAI.getInstance().generativeModel(
modelName = "gemini-2.5-pro",
generationConfig = GenerationConfig.builder()
.maxOutputTokens(512)
.temperature(0.4f) // Low temperature for consistent utility-app suggestions
.build(),
systemInstruction = content {
text(
"""
You are an AI advisor for a wallpaper app.
Based on the user's mood, time of day, and weather,
recommend a wallpaper category and explain why in one sentence.
Always respond in the user's language.
Available categories: nature, minimal, space, warm, cool, abstract, city, art, seasonal
Format: category_name|reason
""".trimIndent()
)
}
)
}
suspend fun recommendCategory(
mood: String,
timeOfDay: String,
weather: String = "unknown"
): RecommendationResult {
return try {
val prompt = "Mood: $mood | Time: $timeOfDay | Weather: $weather"
val response = model.generateContent(content { text(prompt) })
val text = response.text?.trim() ?: return RecommendationResult.Fallback
val parts = text.split("|")
if (parts.size >= 2) {
RecommendationResult.Success(
category = parts[0].trim(),
reason = parts[1].trim()
)
} else {
RecommendationResult.Fallback
}
} catch (e: Exception) {
RecommendationResult.Fallback
}
}
}
sealed class RecommendationResult {
data class Success(val category: String, val reason: String) : RecommendationResult()
object Fallback : RecommendationResult()
}One deliberate choice worth explaining: temperature = 0.4f. For a utility app like this, you want stable, contextually appropriate suggestions — not creative variety. Users who see different category recommendations each time they open the app at the same time of day will lose trust in the feature. Lower temperature means fewer surprises, which is the right call for utility contexts.
The systemInstruction also specifies "one sentence" as the expected response length. AI output that overflows your UI layout and gets truncated creates a poor experience regardless of response quality. Constraining length in the instruction saves defensive code in your UI layer.
Using Antigravity to Accelerate Android Intelligence System Integration
AppFunctions API is still in alpha, which means thin documentation and rapid change. This is exactly when having well-configured AGENTS.md in Antigravity pays off.
# AGENTS.md (Android Intelligence System Integration)
## Project goal
Add Gemini Intelligence support to a wallpaper app (50M+ downloads).
Use AppFunctions API to let users control wallpaper selection via natural language.
## Tech stack
- Android 17 / Kotlin 2.x / Jetpack Compose
- AppFunctions API alpha (androidx.appfunctions:1.0.0-alpha01)
- Firebase AI Logic SDK (Gemini 2.5 Pro)
- EAP-stage API — reference docs at goo.gle/eap-af
## AppFunctions design principles
- Write description and parameter explanations in English (better Gemini accuracy)
- Always include concrete value examples in parameter descriptions
- Error messages and success.message should be in user-facing language
- Default setImmediately to false (wallpaper misapplications are high-friction)
- Use deepLink only for preview flows; execute confirmable actions directly
## Firebase AI Logic principles
- Use temperature 0.3–0.5 for utility app suggestions
- Always constrain response length and format in systemInstruction
- Sanitize and trim AI responses before displaying in UI
## Known constraints (as of 2026-05-14)
- AppFunctions confirmed working on Android 17+
- allowedCallers currently limited to com.google.android.apps.assistant
- EAP registration: goo.gle/eap-afWith this AGENTS.md in place, when you ask Antigravity to add an AppFunction, it generates code with English descriptions, setImmediately defaulting to false, and user-facing error messages — matching your design decisions without requiring repeated explanations.
One particularly effective pattern for alpha APIs: paste EAP sample code directly into AGENTS.md. Antigravity doesn't have training data for APIs in private preview, so giving it the canonical implementation patterns in the AGENTS.md context leads to far more accurate code generation.
Design Decisions from My 50M-Download App Portfolio
After ten years of building apps independently, I know that "update everything immediately" when a new API ships is not how you stay sustainable. Here's how I prioritized Android Intelligence System adoption:
High priority: Core wallpaper app Used daily, so the value of Gemini Intelligence integration is high. "Automatically change wallpaper in the morning" maps to Task Automation. "Select based on mood and weather" needs AppFunctions. Plan: validate Task Automation first, add AppFunctions in three months.
Medium priority: Healing sound app Natural language control ("play work mode music") has clear value. Cross-app synergy with wallpapers (Visual + Sound) is an interesting future direction. Registered for EAP to get more information.
Low priority: Manifestation-category app For these apps, the user's conscious, voluntary action is the product. Automating that interaction might undermine the core value. Watching how the platform evolves before deciding.
What matters as much as the priority ranking is being able to articulate why something is low priority. My grandfather was a temple carpenter who made deliberate decisions about where to use machinery and where to work by hand. He wasn't being stubborn — he was protecting the quality that made the craft meaningful.
I carry that same instinct into app development: being thoughtful about where AI intervention adds value versus where the human act of choosing is the point.
Three Actions to Take Now
Google I/O 2026 is next week (May 19–20). More detailed developer information will come from there. Here's what makes sense to do before that:
1. Test Task Automation behavior this week No code changes needed. If you have a Pixel or Galaxy running the Android 17 preview, try having Gemini navigate your app. Understanding what works out of the box — and what doesn't — tells you exactly what gap AppFunctions needs to fill.
2. Register for the AppFunctions EAP this week
The registration link is goo.gle/eap-af. EAP approval gives you access to full API documentation and developer support. Approval may take a few days, so worth submitting now.
3. Prepare your AGENTS.md for post-I/O integration After Google I/O 2026, the AppFunctions API reference should become more complete. Update your AGENTS.md with that information as soon as it lands. Treating AGENTS.md as a living document that tracks an evolving API is the most effective workflow I've found for building on fast-moving platforms with Antigravity.
Android Intelligence System adoption isn't a single milestone — it's something that matures alongside the platform. I'm looking forward to seeing what next week's I/O announcements reveal.