Hi, everyone! We've just released Chrome 154 (154.0.8037.92) for Android. It'll become available on Google Play over the next few days.
This release includes stability and performance improvements. You can see a full list of the changes in the Git log. If you find a new issue, please let us know by filing a bug.
Android releases contain the same security fixes as their corresponding Desktop releases (Windows & Mac: 154.0.8037.92/.93 Linux: 153.0.8010.92) unless otherwise noted.
The Stable channel has been updated to 154.0.8037.92/.93 for Windows andMac and 154.0.8037.92 to Linux which will roll out over the coming days/weeks. A full list of changes in this build is available in the Log
Security changes will be updated shortly
Interested in switching release channels? Find out how here. If you find a new issue, please let us know by filing a bug. The community help forum is also a great place to reach out for help or learn about common issues.
The Extended Stable channel has been updated to 152.0.7977.149for Windows and Mac which will roll out over the coming days/weeks.
A full list of changes in this build is available in the log. Interested in switching release channels? Find out how here. If you find a new issue, please let us know by filing a bug. The community help forum is also a great place to reach out for help or learn about common issues.
We are upgrading the underlying text-to-speech (TTS) engine powering AI voiceovers and avatar narration in Google Vids to the latest Gemini 3.8 Flash Lite TTS model.
High-quality voiceover is essential for compelling video communication. With this model upgrade, Google Vids creators will experience:
Superior Naturalness & Inflection: Improved sentence flow, lifelike pacing, and context-aware emphasis that reduces robotic cadences.
Fast Generation Latency: Rapid audio synthesis allows you to iterate on scripts and preview voiceovers in real time.
Getting started
Admins: There is no admin control for this feature.
End users: There is no end user setting for this feature. Visit the Help Center to learn more.
Posted by Sheenam Mittal, Senior Product Manager, Google Play
The subscription landscape is evolving rapidly, especially with the surge of generative AI and increasingly sophisticated app experiences. As the ecosystem shifts, we recognize that developers need more flexible and robust tools to monetize effectively while improving the LTV of recurring purchases. On Google Play, we are continuously expanding our subscription platform to help you drive growth, adapt to new business models, and meet your users exactly where they are.
Here is a look at the capabilities we are testing and rolling out to support the next generation of subscriptions, along with powerful existing features designed to maximize your conversion and retention.
Unlock new ways to sell and grow with flexible monetization models
As we look at the next few years of the subscription business, flexibility is paramount. Developers building GenAI tools, entertainment, educational platforms, and business solutions need adaptable pricing and packaging models to scale access beyond the individual user and capture higher cart value at checkout.
Multi-Quantity Subscriptions: Scale subscriptions to teams
To support collaborative and team-wide or group usage, Play is introducing Multi-Quantity Subscription Purchase. This allows users to make multiple subscription purchases in a single transaction and easily assign those as seats or subscriptions to team members or students. This is a game-changer for productivity, EdTech, and GenAI developers looking to sell team-wide subscription access seamlessly.
Usage-Based Billing: Support AI and variable-cost features
For apps with variable computing costs—like AI generation tools or other usage-based services—rigid recurring subscriptions do not always fit. Usage-Based Billing enables you to set up prepaid metered billing where users can automatically top up their balance whenever it falls below a set threshold. This ensures uninterrupted service for your users while protecting your margins.
Beyond these flexible models, we are also making it easier to package your products and upsell creatively at checkout:
Mixed Carts: Sell subscriptions and one-time products in a single checkout
Historically, subscriptions and one-time products were purchased in separate transactions. If a user wanted to buy a monthly membership alongside a starter pack of in-app currency or bonus credits, they had to complete two separate checkout flows.
Mixed Carts bridges this gap for developers who want to sell both auto-renewing subscriptions and one-time products (OTPs). By enabling you to process an auto-renewing base subscription alongside OTPs in a single API call and unified checkout sheet, Mixed Carts streamlines the transaction process.
This unified experience also opens up powerful upsell opportunities for your business—such as offering targeted discounts if an end user purchases a complete bundle of a subscription and complementary in-app items together.
Cross-Developer Bundling: Partner across apps to unlock shared growth
Partnerships are a proven strategy for acquiring new users and driving growth. With Cross-Developer Bundling, you can create and sell a hard bundle of two or more complementary subscriptions in your own catalog.
This capability allows you to team up with other developers—or combine offerings across your own portfolio of apps—to deliver massive value through a single purchase. For example, if you manage a language learning app, you can now create a single SKU that bundles your monthly membership with a partner's premium travel guide subscription, offering users a combined subscription at a discounted rate.
By sharing the acquisition benefits, you can seamlessly reach new audiences and secure more recurring revenue for your business.
Maximize subscription performance: Keep and win back the users you’ve earned
Acquiring a subscriber is only the first step—long-term growth depends on minimizing friction across the billing lifecycle. We are heavily invested in improving subscription performance to help you prevent involuntary payment declines and retain your subscribers.
The In-App Messaging API: Resolve payment declines and price change updates in-context
Available now to all developers, we highly encourage adopting the In-App Messaging API. This tool allows you to meet end users exactly where they are—inside your app—with critical transactional messages. You can use this API to:
Prompt users to fix a payment decline immediately.
Notify users of upcoming price changes transparently.
By handling these critical account states gracefully within the app experience, you can continue running your business without disrupting the user journey. Learn more.
Dynamic Grace Period: Tailor payment recovery windows with predictive models
Involuntary churn from payment declines is often addressed with a static, one-size-fits-all grace period. However, fixed durations force a difficult trade-off between giving users enough time to resolve payment issues and managing developer service costs during unpaid periods. With Dynamic Grace Period, Google Play utilizes machine learning and heuristic models to tailor the grace period duration for individual subscribers following a payment decline. By intelligently matching the recovery window to the user's recovery likelihood, this capability is designed to help developers better balance renewal recovery against unpaid service access. To ensure consistency with your business rules, Google Play automatically adjusts the subsequent account hold duration, preserving your total configured recovery window without requiring client-side code changes.
Retention Offers and Plan Change: Prevent voluntary churn in the cancellation flow
Acquiring new subscribers is expensive, making it critical to engage and retain your existing user base. When users consider canceling, capturing their attention before they leave is essential for protecting your customer lifetime value. With Retention Offers, you can present developer-funded incentives—like a discount—directly within the Play Store cancellation flow.
For users who may not be eligible for a discount or promotional offer, you can suggest a Plan Change to a lower-priced tier, ensuring you offer a flexible path to keep them engaged in your app rather than losing them entirely.
Native Winback Offers: Re-engage lapsed subscribers directly on the Play Store
A canceled subscription doesn’t have to be the end of the user lifecycle. Former subscribers already understand the value of your app—they often just need the right incentive at the perfect moment to return. Traditional winback campaigns rely on email or push notifications, which fall flat if a user has uninstalled your app. Google Play's Subscription Winback Offers close this gap in your re-acquisition strategy by reaching users directly on the Google Play Store, helping you present lapsed users with personalized offers that make coming back easier than ever.
Behind the scenes: The revenue shield you don’t have to build
Alongside the tools you configure in Play Console, Google Play runs a continuous engine of zero-lift optimizations behind the scenes to grow your subscriber base and reduce involuntary churn—without requiring a single line of developer code. From smart payment retries and automatically cycling through backup payment methods for opted-in users, to sending intelligent, context-aware reminders during grace periods and account hold, Play works continuously to recover failed transactions seamlessly.
We also protect your revenue with built-in fraud and abuse prevention systems that block bad actors from exploiting promotional offers or manipulating billing cycles. This ensures your promotional budgets reward legitimate, high-value subscribers—securing your business while naturally lifting overall retention.
Many of these features are currently available or rolling out through our Early Access Program, meaning capabilities are in active testing with select partners to gather feedback before rolling out more broadly in Play Console. If you work with a Google Play partner manager, you can reach out to express interest as programs open. To learn more about our current subscription capabilities and get your app ready for what’s next, explore our Google Play Billing subscriptions documentation.
Explore art and culture with visual-first conversation search, a redesigned home feed, AI experiments and 27 new city guides in the Google Arts & Culture app.
Welcome back to the blog post series "Build intelligent Android apps" where you take a basic Android app and transform it into a personalized, intelligent, and agentic experience. In our previous post you learned how to connect to the intelligence system using AppFunctions.
In this post, you will learn how to build autonomous in-app agentic workflows running in the cloud.
Sometimes a task is too complex for a single device session. For example, booking a complete holiday itinerary involves coordinating flight times, selecting hotel rooms, reserving museum tickets, and planning restaurant reservations. If you run this multi-step process directly on a mobile device, the app might get closed and lose your progress. Managing all these steps and API credentials on a phone also gets complicated quickly.
For these long-running, multi-step workflows, you can use a custom self-hosted backend. The backend executes the booking agents in the background, while the Android app connects to the session, visualizes the progress, and requests user input only when necessary.
Using a cloud-hosted agentic backend offers a few advantages:
Background execution: Booking agents run autonomously in the cloud, so progress is never lost if the mobile app goes to the background or loses internet connectivity.
Complex multi-agent orchestration: A coordinator agent can delegate bookings to specialized subagents and handle dependencies between them.
Client-agnostic UI rendering: The backend describes the interface structure dynamically, letting you update the UI layout without releasing a new client version.
The booking assistant shows all booking progress, organized by event type.
With these benefits in mind, we added a Booking Assistant to Jetpacker that coordinates flights, hotels, museums, and restaurant reservations. Let's look at how we orchestrated a multi-agent system powered by the Agent Development Kit (ADK), with the Agent-User Interaction protocol(AG-UI) and Agent-to-User Interface protocol (A2UI) to send and display interactive cards natively in Jetpack Compose.
Powering complex workflows with ADK agents
Rather than coordinating the orchestration flow manually using custom REST endpoints or complex web sockets, you can use the Agent Development Kit (ADK). With ADK, you can define agents and equip them with python function tools to query databases and execute bookings.
The Android app sends the current trip itinerary data to the server. The coordinator agent chooses which subagents to trigger. Each subagent provides its results to a shared session queue that streams the results back to the Android app.
Here is how to define a simple agent and run it using ADK:
# android/booking-server/booking_server.py
# Note: ADK supports many different coding languages. For now, use the Python version as it includes support for A2UI which we'll use later in this blog post.
from google.adk import Agent
from google.adk.runners import InMemoryRunner
from google.adk.tools import FunctionTool
# Define custom tools to interact with database
def search_flights(destination: str, date: str) -> list[str]:
# In production, here you would query our flight database and return dynamic results
return ["10:00 AM", "2:00 PM"]
def reserve_flight(flight_time: str) -> str:
# In production, here you would save the reservation transaction
return "Reserved flight at " + flight_time
# Instantiate the booking agent with specialized tools
flight_agent = Agent(
name="Flight Booker",
model="gemini-3.1-flash-lite",
instruction="Help the user search for flights and book a reservation.",
tools=[
FunctionTool(search_flights),
FunctionTool(reserve_flight, require_confirmation=True)
]
)
# Run the agent in memory using a session ID
runner = InMemoryRunner(flight_agent)
async for event in runner.run_async(user_id=user_id, session_id=session_id):
if event.content:
print("Agent said:", event.content)
When you run an agent using this setup, ADK manages the execution steps for you. It automatically tracks the conversation context, routes messages between the user and the model, and executes the registered tools when the model requests them. This allows you to focus on writing clean procedural logic while the framework handles the orchestration in the background.
The ADK web interface shows how you can have a conversation with the multi-agent booking system.
To connect this backend agent to our Jetpacker app, the server needs a way to stream updates in real time to the device, which is handled using the AG-UI protocol. The agent also needs a structured way to describe and update interactive components (like option selectors and seating grids) dynamically on the phone, which is where the A2UI protocol comes in.
Standardizing agent-client communication with AG-UI
Running agents in the cloud and rendering UI on Android requires a standard communication channel. For this, you will use the AG-UI protocol.
AG-UI is a bidirectional transport layer protocol that standardizes message types between agents and UI clients. The agent can inform the client of lifecycle events, text messages, tool calls, and state management. The client, in turn, can send user text messages, tool call results, and custom action events back to the agent.
On the server side, it yields updates formatted as standard Server-Sent Events (like event: TEXT_MESSAGE_CONTENT containing the JSON delta). On Android, the Kotlin SDK listens to this stream and automatically maps the payloads to type-safe client events:
// https://github.com/android/ai-samples/tree/main/jetpacker/android/feature/trip/booking_assistant/src/main/kotlin/com/example/jetpacker/feature/booking_assistant/BookingAssistantViewModel.kt
import com.agui.client.agent.HttpAgent
import com.agui.client.agent.HttpAgentConfig
import com.agui.core.types.RunAgentInput
import com.agui.core.types.UserMessage
import com.agui.core.types.TextMessageStartEvent
import com.agui.core.types.TextMessageContentEvent
import com.agui.core.types.TextMessageEndEvent
val config = HttpAgentConfig(
agentId = "booking-assistant",
threadId = threadId,
url = "https://<your-backend-url>"
)
val agent = HttpAgent(config, httpClient)
// Set up the input with the session thread and user instruction
val input = RunAgentInput(
threadId = threadId,
runId = runId,
messages = listOf(UserMessage("Book a flight to Paris"))
)
// Run the agent flow and collect lifecycle events
agent.runAgentObservable(input)
.collect { event ->
when (event) {
is TextMessageStartEvent -> { /* ... */ }
is TextMessageContentEvent -> { /* ... */ }
is TextMessageEndEvent -> {
// Handle the completed message
}
}
}
You can then write a UI to render these different types of standardized AG-UI events. This will give you the prototypical "Chatbot" experience:
A basic interface that lets a user chat with an assistant.
Letting the agent speak UI with A2UI
Traditional chatbots typically return plain text or custom JSON payloads. When building complex interfaces, the client application has to parse these payloads and map them to specific, pre-built screens. This creates a dependency: every time you add a new feature, change the layout, or support a new user interaction, you have to update both the backend agent and the mobile application. This requires publishing an app update and waiting for users to install it.
To solve this, use the A2UI protocol. A2UI allows agents to describe the UI components to render on the client dynamically. The client app declares a catalog of components it supports, and the server sends a JSON payload specifying the component layout and properties:
The server specifies which catalog components to render along with their active property values, cleanly decoupling the client's visual implementation details from the agent's workflow state.
Designing the backend UI schema
For the agent to generate these JSON payloads correctly, it needs to know which components are available and what properties they accept.
To do this, use the ADK A2UI integration. Instead of manually writing prompt instructions for every component in our catalog, the A2uiSchemaManager compiles their JSON schemas and layout instructions directly into the system prompt. This ensures the model learns the exact structure and formatting rules it must follow to generate valid A2UI payloads:
# android/booking-server/booking_server.py
from a2ui.schema.manager import A2uiSchemaManager
from a2ui.schema.constants import VERSION_0_9
from a2ui.schema.catalog import CatalogConfig
from a2ui.basic_catalog.provider import BasicCatalog
# Initialize A2UI Schema Manager with custom booking component catalog
schema_manager = A2uiSchemaManager(
version=VERSION_0_9,
catalogs=[
BasicCatalog.get_config(version=VERSION_0_9),
CatalogConfig.from_path(
name="https://example.com/catalogs/booking_assistant/v1/catalog.json",
catalog_path="booking_catalog.json"
)
]
)
# Compile prompt instructions including the A2UI JSON schema
A2UI_SYSTEM_INSTRUCTION = schema_manager.generate_system_prompt(
role_description="You are a helpful travel booking assistant.",
ui_description="Use InteractiveOptionPicker for choices, SeatSelectionPicker for seat selection...",
include_schema=True,
include_examples=True,
allowed_components=["InteractiveOptionPicker", "SeatSelectionPicker", "BookingStatus"]
)
With this generated system instruction, the LLM is grounded in the schema layout and knows exactly how to formulate component updates that the Android client is capable of rendering.
Natively rendering A2UI with Jetpack Compose
To render these component trees natively on Android, use the new Jetpack Compose A2UI Renderer library.
First, add the dependencies to our module's build.gradle.kts file:
Each component class in the catalog (such as BookingStatusComponent) defines how to map the properties received from the JSON payload into a Jetpack Compose composable function.
Tip: Jetpacker implements custom components (InteractiveOptionPicker, SeatSelectionPicker, BookingStatus) tailored for booking flows. If your agent uses standard elements (such as text, cards, buttons, rows, columns, checkboxes, and date-time pickers), material3-a2ui also provides materialA2uiBasicCatalogV1(...), giving you ready-to-use Material 3 implementations without writing any custom components.
Note: To keep the backend and mobile client aligned, both rely on the same catalog definition ID (https://example.com/catalogs/booking_assistant/v1/catalog.json). If you add or modify properties on the backend catalog, you must increase the version number, and update the matching Kotlin component class to prevent parsing errors.
In the BookingAssistantViewModel, process the A2UI messages using the A2uiMessageProcessor and update our active surfaces:
In the Compose screen, collect these surfaces and render each one using the official A2uiSurface composable from androidx.compose.material3:material3-a2ui. A2uiSurface automatically handles reactive component state observation, Material 3 loading indicators, error fallbacks, and animated transitions between updates:
You will now see several UI surfaces generated by our agent running in the backend:
A well-designed booking assistant that relies on UI instead of text to interact with the user.
Bringing it all together
By hosting agent workflows in the cloud and using the AG-UI and A2UI protocols together, we can build dynamic, native Android interfaces driven directly by AI models. AG-UI establishes the real-time bidirectional streaming channel for messages and lifecycle events, while A2UI enables the cloud agent to dynamically describe interactive UI components, keeping the client application perfectly decoupled from the step-by-step backend orchestration logic.
Check out the other parts of this blog post series:
▪️ Part 1: Introduction of the app and a high-level overview.
📱 Part 2: On-device intelligence. Dive deep into ML Kit’s GenAI APIs and Gemini Nano to build privacy-first features like itinerary summarization, receipt parsing, and local audio processing.
☁️ Part 3: Hybrid and cloud reasoning. Explore how to use Firebase AI Logic to ground LLM answers in real-world data like Google Maps and web context.
⚙️ Part 4: System integration. Integrating with the Android intelligence system using AppFunctions.
🤖 Part 5 (this post!): In-app agentic workflows. Extend the app with end-to-end booking assistants powered by A2UI and ADK.
Interested in more on Android Development? Follow Android Developers on YouTube or LinkedIn!
All code snippets in this blog post follow the following copyright notice:
Copyright 2026 Google LLC.
SPDX-License-Identifier: Apache-2.0