Author Archives:

Build intelligent Android apps: Cloud and hybrid inference

Posted by Thomas Ezan, Jolanda Verhoef, Caren Chang, Senior Developer Relations Engineers, Android Developer Relations



Welcome back to the blog post series "Build intelligent Android apps" where we take a basic Android app and transform it into a personalized, intelligent, and agentic experience. In our previous post we explored how to build intelligent on-device features using Gemini Nano through ML Kit's Prompt API.

In this post, we will look at how you can leverage Firebase AI Logic to build cloud-hosted and hybrid AI features: 

  • Grounding answers in real-world context
  • Routing requests dynamically between cloud and local execution using hybrid inference
  • Translating content with custom routing systems


Sometimes a use case requires AI models with greater world knowledge, a much larger context window, or the ability to handle complex queries. In those scenarios, we can leverage cloud models. 

Other times, you want the best of both worlds: using hybrid inference to run on-device when available to lower costs, while falling back to the cloud to ensure compatibility for all devices.


Cloud and hybrid features in Jetpacker: Museum assistant with web grounding, hybrid restaurant review drafting, and  support chat featuring custom-routed live translation.

Let’s look at how we implemented three cloud and hybrid features in Jetpacker:

  • a museum assistant with web grounding
  • hybrid restaurant review drafting
  • hotel support chat featuring custom-routed live translation.

Use LLM grounding for up-to-date informationMuseum assistant chatbot with LLM grounding

The Museum assistant is an interactive chatbot designed to help users plan their museum visits. It provides visitors with up-to-date details regarding specific exhibits, current opening hours, ticket pricing, and more.


Museum assistant is a chatbot that answers questions, such as 
‘How can I get a ticket discount for Le Louvre?’

When building AI features, getting the model to answer with fresh, accurate, and specific real-world information is a common challenge. While cloud models possess massive amounts of world knowledge, they might not know about seasonal exhibits or the current day’s opening hours. 



Grounding data is added to the context window to enable the model
 to answer questions correctly and accurately.

To bridge this gap, we can use grounding techniques to add extra context to the model’s context window. The Firebase AI Logic SDK supports three types of grounding:

  • URL grounding: Grounding responses using content from a specific webpage (e.g. current ticket prices or museum rules).
  • Google Search grounding: Letting the model query the real-time Google search index for up-to-date details.
  • Maps grounding: Using Google Maps location data.

In Jetpacker, we dynamically construct the available tools based on enabled feature flags and initialize the generative model using the Firebase AI SDK:

// implementation("com.google.firebase:firebase-ai-logic")

private var toolList = mutableListOf<Tool>()

init {
    if (ENABLE_SEARCH_GROUNDING) {
        toolList.add(Tool.googleSearch())
    }
    if (ENABLE_URL_GROUNDING) {
        toolList.add(Tool.urlContext())
    }
}

private val generativeModel = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "gemini-3-flash",
        systemInstruction = content {
            text("You are a helpful museum assistant answering questions about a museum. Use plain text.")
        },
        tools = toolList
    )

When the user queries the assistant, if URL grounding is enabled, we append the specific museum resource URLs directly into the prompt:

val groundingText = if (FeatureFlags.ENABLE_URL_GROUNDING) {
    "\n If the following message above is about the rules and terms to visit Le Louvre, " +
    "if needed answer this urls ${urlList.joinToString()}"
} else {
    ""
}

val prompt = "$text $groundingText"

var response = chat.sendMessage(prompt)

Hybrid inference: On-device review generation with Maps deep link

Not every AI task requires a cloud-based model, and not every device is online. To help developers balance latency, cost, and offline availability, we recently introduced the Firebase API for Hybrid Inference.

In Jetpacker, the restaurant review feature lets users review select topics and automatically drafts a review. To enable this for all users, we prioritize local execution with Gemini Nano, and fall back to cloud models on devices that don’t support Gemini Nano. 


The restaurant review feature uses hybrid inference to draft a review based on topics

// implementation("com.google.firebase:firebase-ai-logic")
// implementation("com.google.firebase:firebase-ai-ondevice:16.0.0-beta03")


// Initialize the model with hybrid routing configuration
val reviewModel = Firebase.ai.generativeModel(
    modelName = "gemini-3.1-flash-lite",
    onDeviceConfig = OnDeviceConfig(
        inferenceMode = InferenceMode.PREFER_ON_DEVICE
    )
)

The Hybrid Inference API supports four distinct routing modes:

  • PREFER_ON_DEVICE: Prioritizes local execution and falls back to cloud if Gemini Nano is unavailable.
  • PREFER_IN_CLOUD: Prioritizes cloud execution and falls back to on-device if the device goes offline.
  • ONLY_ON_DEVICE: Restricts execution strictly to the device.
  • ONLY_IN_CLOUD: Restricts execution strictly to the cloud.

Once the review is generated, we copy it to the clipboard and use an intent to open Google Maps directly to the restaurant's review page, providing a seamless user experience:

private fun copyAndOpenMapsReview(context: Context, reviewText: String, placeId: String) {
    val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    val clip = ClipData.newPlainText("User Review", reviewText)
    clipboard.setPrimaryClip(clip)

    val uri = Uri.parse("https://search.google.com/local/writereview/mobile?placeid=$placeId")
    val intent = Intent(Intent.ACTION_VIEW, uri).apply {
        setPackage("com.google.android.apps.maps")
    }
    context.startActivity(intent)
}

Custom hybrid routing: Hotel support chat translation with simulated personas

The hotel support chat was built to let users finalize logistics and check on hotel details. This feature uses system instructions to configure a localized receptionist assistant. By passing specific information—such as the preferred language and hotel information—in the instructions, we can set up a conversational persona representing a specific hotel.

private val generativeModel = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        systemInstruction = content {
            text("""
              You are a helpful hotel receptionist at $hotelName only speaking $language. 
              Answer politely in $language. The bar closes at 10pm and breakfast is from 7am to 10am.
              There's someone at the desk 24/7. You can retrieve your luggage from the storage room 
              at the back of the lobby at any time.
              """)
        },
        modelName = "gemini-3-flash-preview"
    )

Because receptionist responses are in the hotel's local language (for example, French for Hotel Le Meurice in Paris), we need to translate messages to the user’s preferred language. 


Hotel support chat messages are automatically translated to the user’s preferred language 

While hybrid models can configure simple routing preferences, complex scenarios require custom routing logic. In Jetpacker, we implement a custom routing stack that takes into account:

  • Language identification: Using the on-device ML Kit Language Identification API, we can detect the incoming message language.
  • On-device translation (Gemini Nano): ML Kit’s Prompt API lets us translate common language pairs directly on the device, saving bandwidth and cloud cost.
  • Cloud translation (Gemini 3 Flash): For more complex languages, we use Gemini Flash 3 to get a higher quality translation.
// implementation("com.google.android.gms:play-services-mlkit-language-id:17.0.0") 

// ML Kit for Language Identification (powered by Google Play Services)
private val languageIdentifier = LanguageIdentification.getClient()

// On-device translator model (prefer Gemini Nano) for translating common language pairs
private val hybridTranslationModel = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "gemini-3-flash",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_ON_DEVICE)
    )

// Cloud translator model for more complex language pairs
private val cloudTranslationModel = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "gemini-3-flash"
    )

When a message needs to be translated, we identify the source language and apply our custom routing logic, executing either on-device or cloud translation:

fun translateMessage(message: SupportChatMessage) {
    viewModelScope.launch {
        // 1. Detect language using ML Kit Language Identification
        val sourceLang = try {
            Tasks.await(languageIdentifier.identifyLanguage(message.text))
        } catch (e: Exception) {
            "Undefined"
        }

        // 2. Custom routing: we've verified the translation quality for English and Korean with Gemini Nano, and will translate message on-device for those two languages
        val routeToCloud = sourceLang != "en" && sourceLang != "kr"

        val prompt = "Translate the following text to $selectedLanguage. Just return the translated sentence: ${message.text}."

        val (translatedText, routePrefix) = if (routeToCloud) {
            val result = cloudTranslationModel.generateContent(prompt)
            result.text to "[Cloud]"
        } else {
            val result = hybridTranslationModel.generateContent(prompt)
            result.text to "[On-Device]"
        }

        if (translatedText != null) {
            _translations.update { current ->
                current + (message.id to "$routePrefix: $translatedText")
            }
        }
    }
}

In this example, the custom routing logic only takes into consideration the translation’s source and target language. However, based on your app’s use case, you can expand the routing logic to include other factors such as the on-device model version, network connectivity, battery status, and more.

Securing the AI Pipelines: Firebase App Check

Lastly, using AI in the cloud opens up possibilities of API key abuse or unauthorized billing. To secure API calls, we integrated Firebase App Check using both Play Integrity (production) and the local Debug Provider (for local development or emulators).

In the JetPackerApplication.kt file, we install the debug provider at startup and trigger anonymous authentication to establish a secure user session:

//  implementation("com.google.firebase:firebase-appcheck-playintegrity") 
//  implementation("com.google.firebase:firebase-appcheck-debug")  
//  implementation("com.google.firebase:firebase-auth") 

override fun onCreate() {
    super.onCreate()
    Firebase.initialize(context = this)
    Firebase.appCheck.installAppCheckProviderFactory(
        DebugAppCheckProviderFactory.getInstance()
    )
    Firebase.auth.signInAnonymously()
}

When building locally on an emulator, App Check prints a local token secret to logcat:

Enter this debug secret into the allow list in the Firebase Console: a8c2dd4c-xxxx-xxxx-xxxx-ef6c114ba27e

Once registered in the Firebase console, local requests are fully verified and authenticated by App Check, protecting our backend while letting us test the app locally.

Conclusion

By combining cloud model capabilities (grounding, system instructions) with on-device capabilities (hybrid routing, translation, security app checks), we created a travel app that is smart, secure, and available offline.

Check out the full source code for Jetpacker on GitHub, and explore the Firebase documentation to get started:

Firebase AI Logic Documentation
Firebase Hybrid Inference API

Learn more

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. Deep-dive 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 (this post!): 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 (coming soon): In-app agentic workflows. Extend the app with an end-to-end booking assistant 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

Run Ray on TPU, Part 1: The foundations

Ray 2.55 introduces official, first-class support for Google Cloud TPUs, enabling developers to run distributed Python workloads on Google's accelerators using the familiar Ray task-and-actor APIs. To handle the strict networking requirement of keeping multi-host TPU "slices" together over their Inter-Chip Interconnect (ICI), the KubeRay Operator on GKE automatically provisions and labels the underlying hardware layout. Ray Core utilizes these labels via its slice_placement_group() primitive to atomically reserve complete slices, allowing developers to deploy jobs through KubeRay, Ray Train, or Ray Serve simply by declaring a hardware topology (like "4x4") without writing custom placement code.

Import and create combo charts in Google Sheets

Google Sheets now offers enhanced support for combo charts, providing a more seamless experience when creating multi-series visualizations. Users can create new “Combo” chart types, enabling complex dataset visualization with different scales and metrics without requiring manual re-plotting. These include:

  • Clustered Column - Line
  • Clustered Column - Line on Secondary Axis
  • Custom Combo
Sheets combo chart support also comes with enhanced Microsoft Excel import compatibility. Previously, importing external files that contained combo charts with a secondary axis would result in the secondary axis being dropped. This update ensures that secondary axis configurations and combo chart types are preserved during file import.


User creating a combo chart in Google Sheets

Getting started

Rollout pace

Availability

  • Available to all Google Workspace customers and users with personal Google accounts

Resources

Enabling Local Inventory Ads by Default for Shopping Campaigns starting on August 31, 2026

What is changing?

On August 31, 2026, we are aligning Shopping campaigns with Performance Max for Retail campaigns by enabling Local Inventory Ads (LIA) by default. Previously, developers and advertisers had to explicitly set the enable_local field to true within a campaign's ShoppingSetting in order to serve products in their LIA feed.

With this change, the Campaign.ShoppingSetting.enable_local field will no longer have any effect on Shopping campaigns. The Google Ads API backend will automatically override this value to true for all Shopping campaigns, effectively turning on the "Local products" setting behind the scenes.

What you need to do

For v25.1 and future versions, you’ll need to update your code to avoid setting enable_local to false, otherwise you will see a ContextError.OPERATION_NOT_PERMITTED_FOR_CONTEXT error. For any versions prior to v25.1, no immediate code changes are required, and any requests to mutate the enable_local field for a Shopping campaign will treat the value as true.

If you previously relied on setting enable_local to false to prevent local offers from serving in specific Shopping campaigns, you should instead use the CampaignCriterionService to add a listing scope with product_channel set to ONLINE, or use the "Inventory filter" section in the campaign settings UI to filter out local inventory and silo budgets by channel (Online vs. Local).

Note that this change only applies to Shopping campaigns. The enable_local field will continue to function as before for other supported campaign types, such as Performance Max and Demand Gen.

If you have any questions or want to discuss this post, please reach out to us on our “Google Advertising and Measurement Community” Discord server.

Upcoming Changes to the Nearby Connections API

Posted by Wei Wang, Engineering Manager, Android BeTo

User privacy and transparency are core to the Android experience. To better align with these principles, we are updating the default behavior of the Nearby Connections API regarding how it interacts with device radios.

What is changing?

Previously, the Nearby Connections API could automatically toggle Wi-Fi and Bluetooth radios ON to facilitate connections without explicit user intervention. Moving forward, the API will no longer automatically enable these radios for 1P and 3P applications.

What this means for developers

If your app relies on Nearby Connections, you will need to update your implementation to account for these changes:

  • Manual Radio Management: You must ensure that the necessary radios (Wi-Fi or Bluetooth) are enabled before initiating Nearby Connections tasks.
  • User Notification: If the required radios are disabled, your app must now inform the user and request that they enable them manually. The API will no longer programmatically turn them on for you.

Timing

These changes are scheduled to take effect in late 2026. We recommend reviewing your connection workflows now to ensure a seamless transition for your users.

Google Workspace Weekly Recap – July 17, 2026

Google Credential Provider for Windows (GCPW) now supports FIDO2-compliant physical security keys as a second factor for authentication

Google Credential Provider for Windows (GCPW) has been updated to support FIDO2-compliant physical security keys as a second factor for authentication. This update helps organizations improve their security posture by enabling administrators to enforce 2-Step Verification (2SV) using hardware security keys at the Windows login screen. | Learn more.

Improvement to in-room problem reporting for Google Meet hardware

Maintaining an enterprise-grade video conferencing environment requires visibility into the health of its devices. We're introducing new ways to see Google Meet hardware user-reported feedback directly in the Admin console. | Learn more.

New refinement capabilities allow custom editing with Help me write in Gmail

Users can now edit and revise their email drafts in Gmail via the prompt bar, using custom refine instructions in Help me write. Previously the refines were limited to preset options like Polish, Formalize, and Shorten. | Learn more.

Now available: group conversations with external collaborators in Google Chat

For many teams, it’s essential to be able to work in real-time with partners from outside your organization. We’re improving external collaboration in Google Chat by making it possible to create group conversations that include external users. | Learn more.

NotebookLM is now Gemini Notebook

We’re renaming NotebookLM to Gemini Notebook. While it remains a standalone product focused on being your premier research tool, the new name reflects how it will evolve to do more across the Google ecosystem. | Learn more.

Easily control the emotions and pacing of AI avatars and AI voiceovers in Google Vids

Users can now easily steer voiceover and avatar speaking in Google Vids by typing content within brackets like “[excitedly]”. | Learn more.

Expanded language support for Gemini in Google Docs

We are now expanding support for these features to 11 more languages, including Mandarin, Dutch, Malay, Hebrew, Polish, Turkish, Czech, Indonesian, Swedish, Danish, and Norwegian. These new additions join our previously supported languages: English, Spanish, Portuguese, Japanese, French, Korean, German, and Italian. | Learn more.

Generate higher quality AI video clips and edit any video with Gemini Omni in Vids

Users now have access to Gemini Omni directly within Google Vids. Omni provides higher quality video generation with significant improvements over previous models. Additionally, Omni’s world understanding unlocks simple video edits so you can ask Omni to tweak the video you have to get the video you need. | Learn more.

Cast yourself in AI video clips using your personal avatar with Gemini Omni in Vids

Users now have access to Gemini Omni directly within Google Vids. With Gemini Omni, you can create videos using your personal avatar to scale your presence without the studio time. Use a secure verification process to capture your likeness and then select it as a character in Omni generations within Vids. | Learn more.

New Google Meet 'Take notes for me' settings for admins and end users

To help users remember to capture notes for meetings when it’s most valuable, we’re updating the admin and end user settings that let them pre-configure AI note-taking for Google Meet. | Learn more.

The announcements above were published on the Workspace Updates blog over the last week. Please refer to the original blog posts for complete details.

Investing in the Future with the Boys and Girls Club

When asked to describe the impact of gFiber’s partnership with the Boys & Girls Club of Pocatello and Chubbuck in one word, Executive Director Mona Mannan said: "opportunity."

"GFiber is not just funding programming for the kids, it’s actually giving the program the opportunity that these kids and these families wouldn't usually have. [It's] investing in the future of people in Pocatello... we're removing barriers." — Mona Mannan

For local families, this partnership is more than just a summertime activity; it is a dedicated educational space for skill building. Each summer, the Club has provided youth with a safe environment while their parents are at work but, instead of sitting with tablets these elementary students are diving into real-world concepts. From designing electricity boards, building miniature robotics, lava lamps, and planning pathways for toy cars - this STEM curriculum is designed to stimulate screen-free, hands-on critical thinking. 

Thumbnail

"There are hardly any screens, outside of movie day which happens every few weeks," Mannan explained. "It’s all hands-on learning. We want them working with their hands, building, working together in groups, and staying active daily so they don't experience summer learning loss." Summer learning loss refers to knowledge or skills that fade when children are not mentally engaged on a regular basis like they are while at school. At the Boys and Girls Club of Pocatello and Chubbuck, this screen-free intention around learning is to motivate students to build their ideas offline and take their learning into the real world to see what actually works to improve their favorite experiments. Through GFiber’s support the learning experiences happen outside of the Club too, with field trips to Zoo Idaho focusing on biology and the bowling alley for a fun lesson on mass and force.  



The enrichment doesn’t stop when summer ends either, The Boys and Girls Club transitions into an after-school program that follows the District 25 calendar. Students receive homework support during "Power Hour," participate in a brand new expanded music program, and connect with community mentors from the fire department, police department, and Idaho State University student volunteers. The Club also utilizes trauma-informed care training to ensure staff can deeply support children from all backgrounds. This is made possible through strong community alliances and gFiber’s $10,000 annual contribution to the Club. Every dollar donated goes straight back into local operation, programming, and scholarships.

There is an alignment between GFiber’s mission and the Club’s goal of helping youth reach their full potential, as both organizations are dedicated to building a brighter, more connected future. For Mannan, the relationship is built on mutual respect and shared energy, personified by GFiber’s area representative Alberto Garcia, who initiated the partnership. "This has been amazing support for us to grow our program," Mannan shared. "You guys are really an important part of this community."

Chrome Dev for Desktop Update

The Dev channel has been updated to 152.0.7953.3 for Windows, Mac and Linux.

A partial list of changes is available in the Git log. Interested in switching release channels? Find out how. 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.

Chrome Release Team
Google Chrome