Android Developers Blog's Avatar

Android Developers Blog

@android-developers.googleblog.com.web.brid.gy

News and insights on the Android platform, developer tools, and events. [bridged from https://android-developers.googleblog.com/ on the web: https://fed.brid.gy/web/android-developers.googleblog.com ]

257
Followers
0
Following
767
Posts
20.08.2024
Joined
Posts Following

Latest posts by Android Developers Blog @android-developers.googleblog.com.web.brid.gy

Preview
Instagram and Facebook deliver instant playback and boost user engagement with Media3 PreloadManager __ _Posted by  Mayuri Khinvasara Khabya, Developer Relations Engineer __(LinkedIn and X)_ In the dynamic world of social media, user attention is won or lost quickly. Meta apps (Facebook and Instagram) are among the world's largest social platforms and serve billions of users globally. For Meta, delivering videos seamlessly isn't just a feature, it's the core of their user experience. Short-form videos, particularly Facebook Newsfeed and Instagram Reels, have become a primary driver of engagement. They enable creative expression and rapid content consumption; connecting and entertaining people around the world. This blog post takes you through the journey of how Meta transformed video playback for billions by delivering true instant playback. **The latency gap in short form videos** Short-form videos lead to highly fast paced interactions as users quickly scroll through their feeds. Delivering a seamless transition between videos in an ever-changing feed introduces unique hurdles for instantaneous playback. Hence we need solutions that go beyond traditional disk caching and standard reactive playback strategies. **The path forward with Media3 PreloadManager** To address the shifts in consumption habits from rise in short form content and the limitations of traditional long form playback architecture, Jetpack Media3 introduced PreloadManager. This component allows developers to move beyond disk caching, offering granular control and customization to keep media ready in memory before the user hits play. Read this blog series to understand technical details about media playback with PreloadManager. **How Meta achieved true instant playback** **Existing Complexities** Previously, Meta used a combination of warmup (to get players ready) and prefetch (to cache content on disk) for video delivery. While these methods helped improve network efficiency, they introduced significant challenges. Warmup required instantiating multiple player instances sequentially, which consumed significant memory and limited preloading to only a few videos. This high resource demand meant that a more scalable robust solution could be applied to deliver the instant playback expected on modern, fast-scrolling social feeds. ** Integrating Media3 PreloadManager** To achieve truly instant playback, Meta's Media Foundation Client team integrated the Jetpack Media3 PreloadManager into Facebook and Instagram. They chose the DefaultPreloadManager to unify their preloading and playback systems. This integration required refactoring Meta's existing architecture to enable efficient resource sharing between the PreloadManager and ExoPlayer instances. This strategic shift provided a key architectural advantage: the ability to parallelize preloading tasks and manage many videos using a single player instance. This dramatically increased preloading capacity while eliminating the high memory complexities of their previous approach. ** ** ### Optimization and Performance Tuning The team then performed extensive testing and iterations to optimize performance across Meta's diverse global device ecosystem. Initial aggressive preloading sometimes caused issues, including increased memory usage and scroll performance slowdowns. To solve this, they fine-tuned the implementation by using careful memory measurements, considering device fragmentation, and tailoring the system to specific UI patterns. **Fine tuning implementation to specific UI patterns** Meta applied different preloading strategies and tailored the behavior to match the specific UI patterns of each app: * Facebook Newsfeed: The UI prioritizes the video currently coming into view. The manager preloads only the current video to ensure it starts the moment the user pauses their scroll. This "current-only" focus minimizes data and memory footprints in an environment where users may see many static posts between videos. While the system is presently designed to preload just the video in view, it can be adjusted to also preload upcoming (future) videos. * Instagram Reels: This is a pure video environment where users swipe vertically. For this UI, the team implemented an "adjacent preload" strategy. The PreloadManager keeps the videos immediately after the current Reel ready in memory. This bi-directional approach ensures that whether a user swipes up or down, the transition remains instant and smooth. The result was a dramatic improvement in the Quality of Experience (QoE) including improvements in Playback Start and Time to First Frame for the user. ### Scaling for a diverse global device ecosystem Scaling a high-performance video stack across billions of devices requires more than just aggressive preloading; it requires intelligence. Meta faced initial challenges with memory pressure and scroll lag, particularly on mid-to-low-end hardware. To solve this, they built a Device Stress Detection system around the Media3 implementation. The apps now monitor I/O and CPU signals in real-time. If a device is under heavy load, preloading is paused to prioritize UI responsiveness. ** ** This device-aware optimization ensures that the benefit of instant playback doesn't come at the cost of system stability, allowing even users on older hardware to experience a smoother, uninterrupted feed. ### Architectural wins and code health Beyond the user-facing metrics, the migration to Media3 PreloadManageroffered long-term architectural benefits. While the integration and tuning process needed multiple iterations to balance performance, the resulting codebase is more maintainable. The team found that the PreloadManager API integrated cleanly with the existing Media3 ecosystem, allowing for better resource sharing. For Meta, the adoption of Media3 PreloadManager was a strategic investment in the future of video consumption. ** ** By adopting preloading and adding device-intelligent gates, they successfully increased total watch time on their apps and improved the overall engagement of their global community. **Resulting impact on Instagram and Facebook** The proactive architecture delivered immediate and measurable improvements across both platforms. ** ** * Facebook experienced faster playback starts, decreased playback stall rates and a reduction in bad sessions (like rebuffering, delayed start time, lower quality,etc) which overall resulted in higher watch time. * Instagram saw faster playback starts and an increase in total watch time. Eliminating join latency (the interval from the user's action to the first frame display) directly increased engagement metrics. The fewer interruptions due to reduced buffering meant users watched more content, which showed through engagement metrics. **Key engineering learnings at scale** As media consumption habits evolve, the demand for instant experiences will continue to grow. Implementing proactive memory management and optimizing for scale and device diversity ensures your application can meet these expectations efficiently. * Prioritize intelligent preloading Focus on delivering a reliable experience by minimizing stutters and loading times through preloading. Rather than simple disk caching, leveraging memory-level preloading ensures that content is ready the moment a user interacts with it. * Align your implementation with UI patterns Customize preloading behavior as per your apps’s UI. For example, use a "current-only" focus for mixed feeds like Facebook to save memory, and an "adjacent preload" strategy for vertical environments like Instagram Reels. ## * Leverage Media3 for long-term code health Integrating with Media3 APIs rather than a custom caching solution allows for better resource sharing between the player and the PreloadManager, enabling you to manage multiple videos with a single player instance. This results in a future-proof codebase that is easier for engineering teams to not only maintain and optimize over time but also benefit from the latest feature updates. * Implement device aware optimizations Broaden your market reach by testing on various devices, including mid-to-low-end models. Use real-time signals like CPU, memory, and I/O to adapt features and resource usage dynamically. # **Learn More** To get started and learn more, visit  * Explore the Media3 PreloadManager documentation. * Read the blog series for advanced technical and implementation details. * Part 1: Introducing Preloading with Media3 * Part 2: A deep dive into Media3's PreloadManager * Check out the sample app to see preloading in action. Now you know the secrets for instant playback. Go try them out!
05.03.2026 18:03 👍 0 🔁 0 💬 0 📌 0
Preview
Elevating AI-assisted Android development and improving LLMs with Android Bench Posted by Matthew McCullough, VP of Product Management, Android Developer We want to make it faster and easier for you to build high-quality Android apps, and one way we’re helping you be more productive is by putting AI at your fingertips. We know you want AI that truly understands the nuances of the Android platform, which is why we’ve been measuring how LLMs perform Android development tasks. Today we released the first version of Android Bench, our official leaderboard of LLMs for Android development. Our goal is to provide model creators with a benchmark to evaluate LLM capabilities for Android development. By establishing a clear, reliable baseline for what high quality Android development looks like, we’re helping model creators identify gaps and accelerate improvements—which empowers developers to work more efficiently with a wider range of helpful models to choose for AI assistance—which ultimately will lead to higher quality apps across the Android ecosystem. Designed with real-world Android development tasks We created the benchmark by curating a task set against a range of common Android development areas. It is composed of real challenges of varying difficulty, sourced from public GitHub Android repositories. Scenarios include resolving breaking changes across Android releases, domain-specific tasks like networking on wearables, and migrating to the latest version of Jetpack Compose, to name a few. Each evaluation attempts to have an LLM fix the issue reported in the task, which we then verify using unit or instrumentation tests. This model-agnostic approach allows us to measure a model’s ability to navigate complex codebases, understand dependencies, and solve the kind of problems you encounter every day. We validated this methodology with several LLM makers, including JetBrains. > “Measuring AI’s impact on Android is a massive challenge, so it’s great to see a framework that’s this sound and realistic. While we’re active in benchmarking ourselves, Android Bench is a unique and welcome addition. This methodology is exactly the kind of rigorous evaluation Android developers need right now.” > - Kirill Smelov, Head of AI Integrations at JetBrains. The first Android Bench results For this initial release, we wanted to purely measure model performance and not focus on agentic or tool use. The models were able to successfully complete 16-72% of the tasks. This is a wide range that demonstrates some LLMs already have a strong baseline for Android knowledge, while others have more room for improvement. Regardless of where the models are at now, we’re anticipating continued improvement as we encourage LLM makers to enhance their models for Android development. The LLM with the highest average score for this first release is Gemini 3.1 Pro, followed closely by Claude Opus 4.6. You can try all of the models we evaluated for AI assistance for your Android projects by using API keys in the latest stable version of Android Studio. Providing developers and LLM makers with transparency We value an open and transparent approach, so we made our methodology, dataset, and test harness publicly available on GitHub. One challenge for any public benchmark is the risk of data contamination, where models may have seen evaluation tasks during their training process. We have taken measures to ensure our results reflect genuine reasoning rather than memorization or guessing, including a thorough manual review of agent trajectories, or the integration of a canary string to discourage training. Looking ahead, we will continue to evolve our methodology to preserve the integrity of the dataset, while also making improvements for future releases of the benchmark—for example, growing the quantity and complexity of tasks. We’re looking forward to how Android Bench can improve AI assistance long-term. Our vision is to close the gap between concept and quality code. We're building the foundation for a future where no matter what you imagine, you can build it on Android.
05.03.2026 14:03 👍 0 🔁 0 💬 0 📌 0
Preview
Battery Technical Quality Enforcement is Here: How to Optimize Common Wake Lock Use Cases __ _Posted by Alice Yuan, Senior Developer Relations Engineer_ In recognition that excessive battery drain is top of mind for Android users, Google has been taking significant steps to help developers build more power-efficient apps. On March 1st, 2026, Google Play Store began rolling out the wake lock technical quality treatments to improve battery drain. This treatment will roll out gradually to impacted apps over the following weeks. Apps that consistently exceed the "Excessive Partial Wake Lock" threshold in Android vitals may see tangible impacts on their store presence, including warnings on their store listing and exclusion from discovery surfaces such as recommendations. Users may see a warning on your store listing if your app exceeds the bad behavior threshold. This initiative elevated battery efficiency to a core vital metric alongside stability metrics like crashes and ANRs. The "bad behavior threshold" is defined as holding a non-exempted partial wake lock for at least two hours on average while the screen is off in more than 5% of user sessions in the past 28 days. A wake lock is exempted if it is a system held wake lock that offers clear user benefits that cannot be further optimized, such as audio playback, location access, or user-initiated data transfer. You can view the full definition of excessive wake locks in our Android vitals documentation. As part of our ongoing initiative to improve battery life across the Android ecosystem, we have analyzed thousands of apps and how they use partial wake locks. While wake locks are sometimes necessary, we often see apps holding them inefficiently or unnecessarily, when more efficient solutions exist. This blog will go over the most common scenarios where excessive wake locks occur and our recommendations for optimizing wake locks.  We have already seen measurable success from partners like WHOOP, who leveraged these recommendations to optimize their background behavior. **Using a foreground service vs partial wake locks** We’ve often seen developers struggle to understand the difference between two concepts when doing background execution: foreground service and partial wake locks. A foreground service is a lifecycle API that signals to the system that an app is performing user-perceptible work and should not be killed to reclaim memory, but it does not automatically prevent the CPU from sleeping when the screen turns off. In contrast, a partial wake lock is a mechanism specifically designed to keep the CPU running even while the screen is off. While a foreground service is often necessary to continue a user action, a manual acquisition of a partial wake lock is only necessary in conjunction with a foreground service for the duration of the CPU activity. In addition, you don't need to use a wake lock if you're already utilizing an API that keeps the device awake. Refer to the flow chart in Choose the right API to keep the device awake to ensure you have a strong understanding of what tool to use to avoid acquiring a wake lock in scenarios where it’s not necessary. **Third party libraries acquiring wake locks** It is common for an app to discover that it is flagged for excessive wake locks held by a third-party SDK or system API acting on its behalf. To identify and resolve these wake locks, we recommend the following steps: * Check Android vitals: Find the exact name of the offending wake lock in the excessive partial wake locks dashboard. Cross-reference this name with the Identify wake locks created by other APIs guidance to see if it was created by a known system API or Jetpack library. If it is, you may need to optimize your usage of the API and can refer to the recommended guidance. * Capture a System Trace: If the wake lock cannot be easily identified, reproduce the wake lock issue locally using a system trace and inspect it with the Perfetto UI. You can learn more about how to do this in the Debugging other types of excessive wake locks section of this blog post. * Evaluate Alternatives: If an inefficient third-party library is responsible and cannot be configured to respect battery life, consider communicating the issue with the SDK's owners, finding an alternative SDK or building the functionality in-house. **Common wake lock scenarios** Below is a breakdown of some of the specific use cases we have reviewed, along with the recommended path to optimize your wake lock implementation. **User-Initiated Upload or Download** Example use cases: * Video streaming apps where the user triggers a download of a large file for offline access. * Media backup apps where the user triggers uploading their recent photos via a notification prompt. How to reduce wake locks: * Do not acquire a manual wake lock. Instead, use the User-Initiated Data Transfer (UIDT) API. This is the designated path for long running data transfer tasks initiated by the user, and it is exempted from excessive wake lock calculations. **One-Time or Periodic Background Syncs** Example use cases: * An app performs periodic background syncs to fetch data for offline access. * Pedometer apps that fetch step count periodically. How to reduce wake locks: * Do not acquire a manual wake lock. Use WorkManager configured for one-time or periodic work.  WorkManager respects system health by batching tasks and has a minimum periodic interval (15 minutes), which is generally sufficient for background updates. * If you identify wake locks created by WorkManager or JobScheduler with high wake lock usage, it may be because you’ve misconfigured your worker to not complete in certain scenarios. Consider analyzing the worker stop reasons, particularly if you’re seeing high occurrences of STOP_REASON_TIMEOUT. workManager.getWorkInfoByIdFlow(syncWorker.id) .collect { workInfo -> if (workInfo != null) { val stopReason = workInfo.stopReason logStopReason(syncWorker.id, stopReason) } } * In addition to logging worker stop reasons, refer to our documentation on debugging your workers. Also, consider collecting and analyzing system traces to understand when wake locks are acquired and released. * Finally, check out our case study with WHOOP, where they were able to discover an issue with configuration of their workers and reduce their wake lock impact significantly. ### Bluetooth Communication Example use cases: * Companion device app prompts the user to pair their Bluetooth external device. * Companion device app listens for hardware events on an external device and user visible change in notification. * Companion device app’s user initiates a file transfer between the mobile and bluetooth device. * Companion device app performs occasional firmware updates to an external device via Bluetooth. How to reduce wake locks: * Use companion device pairing to pair Bluetooth devices to avoid acquiring a manual wake lock during Bluetooth pairing. * Consult the Communicate in the background guidance to understand how to do background Bluetooth communication. * Using WorkManager is often sufficient if there is no user impact to a delayed communication. If a manual wake lock is deemed necessary, only hold the wake lock for the duration of Bluetooth activity or processing of the activity data. ### Location Tracking Example use cases: * Fitness apps that cache location data for later upload such as plotting running routes * Food delivery apps that pull location data at a high frequency to update progress of delivery in a notification or widget UI. How to reduce wake locks: * Consult our guidance to Optimize location usage. Consider implementing timeouts, leveraging location request batching, or utilizing passive location updates to ensure battery efficiency. * When requesting location updates using the FusedLocationProvider or LocationManager APIs, the system automatically triggers a device wake-up during the location event callback. This brief, system-managed wake lock is exempted from excessive partial wake lock calculations. * Avoid acquiring a separate, continuous wake lock for caching location data, as this is redundant. Instead, persist location events in memory or local storage and leverage WorkManager to process them at periodic intervals. override fun onCreate(savedInstanceState: Bundle?) { locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult?) { locationResult ?: return // System wakes up CPU for short duration for (location in locationResult.locations){ // Store data in memory to process at another time } } } } ### High Frequency Sensor Monitoring Example use cases: * Pedometer apps that passively collect steps, or distance traveled. * Safety apps that monitor the device sensors for rapid changes in real time, to provide features such as crash detection or fall detection. How to reduce wake locks: * If using SensorManager, reduce usage to periodic intervals and only when the user has explicitly granted access through a UI interaction. High frequency sensor monitoring can drain the battery heavily due to the number of CPU wake-ups and processing that occurs. * If you’re tracking step counts or distance traveled, rather than using SensorManager, leverage Recording API or consider utilizing Health Connect to access historical and aggregated device step counts to capture data in a battery-efficient manner. * If you’re registering a sensor with SensorManager, specify a maxReportLatencyUs of 30 seconds or more to leverage sensor batching to minimize the frequency of CPU interrupts. When the device is subsequently woken by another trigger such as a user interaction, location retrieval, or a scheduled job, the system will immediately dispatch the cached sensor data. val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) sensorManager.registerListener(this, accelerometer, samplingPeriodUs, // How often to sample data maxReportLatencyUs // Key for sensor batching ) * If your app requires both location and sensor data, synchronize their event retrieval and processing. By piggybacking sensor readings onto the brief wake lock the system holds for location updates, you avoid needing a wake lock to keep the CPU awake. Use a worker or a short-duration wake lock to handle the upload and processing of this combined data. ### Remote Messaging Example use cases: * Video or sound monitoring companion apps that need to monitor events that occur on an external device connected using a local network. * Messaging apps that maintain a network socket connection with the desktop variant. How to reduce wake locks: * If the network events can be processed on the server side, use FCM to receive information on the client. You may choose to schedule an expedited worker if additional processing of FCM data is required. * If events must be processed on the client side via a socket connection, a wake lock is not needed to listen for event interrupts. When data packets arrive at the Wi-Fi or Cellular radio, the radio hardware triggers a hardware interrupt in the form of a kernel wake lock. You may then choose to schedule a worker or acquire a wake lock to process the data. * For example, if you’re using ktor-network to listen for data packets on a network socket, you should only acquire a wake lock when packets have been delivered to the client and need to be processed. val readChannel = socket.openReadChannel() while (!readChannel.isClosedForRead) { // CPU can safely sleep here while waiting for the next packet val packet = readChannel.readRemaining(1024) if (!packet.isEmpty) { // Data Arrived: The system woke the CPU and we should keep it awake via manual wake lock (urgent) or scheduling a worker (non-urgent) performWorkWithWakeLock { val data = packet.readBytes() // Additional logic to process data packets } } } ## Summary By adopting these recommended solutions for common use cases like background syncs, location tracking, sensor monitoring and network communication, developers can work towards reducing unnecessary wake lock usage. To continue learning, read our other technical blog post or watch our technical video on how to discover and debug wake locks: Optimize your app battery using Android vitals wake lock metric. Also, consult our updated wakelock documentation. To help us continue improving our technical resources, please share any additional feedback on our guidance in our documentation feedback survey.
05.03.2026 00:00 👍 0 🔁 0 💬 0 📌 0
Preview
How WHOOP decreased excessive partial wake lock sessions by over 90% _Posted by Breana Tate, Developer Relations Engineer, Mayank Saini, Senior Android Engineer, Sarthak Jagetia, Senior Android Engineer and Manmeet Tuteja, Android Engineer II_ Building an Android app for a wearable means the real work starts when the screen turns off. WHOOP helps members understand how their body responds to training, recovery, sleep, and stress, and for the many WHOOP members on Android, reliable background syncing and connectivity are what make those insights possible. ** ** Earlier this year, Google Play released a new metric in Android vitals: Excessive partial wake locks. This metric measures the percentage of user sessions where cumulative, non-exempt wake lock usage exceeds 2 hours in a 24-hour period. The aim of this metric is to help you identify and address possible sources of battery drain, which is crucial for delivering a great user experience. ** ** Beginning March 1, 2026, apps that continue to not meet the quality threshold may be excluded from Google Play discovery surfaces. A warning may also be placed on the Google Play Store listing, indicating the app might use more battery than expected. According to Mayank Saini, Senior Android Engineer at WHOOP,  this “presented the team with an opportunity to raise the bar on Android efficiency,” after Android vitals flagged the app’s excessive partial wake lock % as 15%—which exceeded the recommended 5% threshold. The team viewed the Android vitals metric as a clear signal that their background work was holding the CPU awake longer than necessary. Resolving this would allow them to continue to deliver a great user experience while simultaneously decreasing wasted background time and maintaining reliable and timely Bluetooth connectivity and syncing. ** ** Identifying the issue ** ** To figure out where to get started, the team first turned to Android vitals for more insight into which wake locks were affecting the metric. By consulting the Android vitals excessive partial wake locks dashboard, they were able to identify the biggest contributor to excessive partial wake locks as one of their WorkManager workers (identified in the dashboard as androidx.work.impl.background.systemjob.SystemJobService). To support the WHOOP “always-on experience”, the app uses WorkManager for background tasks like periodic syncing and delivering recurring updates to the wearable. ** ** While the team was aware that WorkManager acquires a wake lock while executing tasks in the background, they previously did not have visibility into how all of their background work (beyond just WorkManager) was distributed until the introduction of the excessive partial wake locks metric in Android vitals. ** ** With the dashboard identifying WorkManager as the main contributor, the team was then able to focus their efforts on identifying which of their workers was contributing the most and work towards resolving the issue. ** ** Making use of internal metrics and data to better narrow down the cause ** ** WHOOP already had internal infrastructure set up to monitor WorkManager metrics. They periodically monitor: 1. Average Runtime: For how long does the worker run? 2. Timeouts: How often is the worker timing out instead of completing? 3. Retries: How often does the worker retry if the work timed out or failed? 4. Cancellations: How often was the work cancelled? ** ** Tracking more than just worker successes and failures gives the team visibility into their work’s efficiency. ** ** The internal metrics flagged high average runtime for a select few workers, enabling them to narrow the investigation down even further. ** ** In addition to their internal metrics, the team also used Android Studio’s Background Task Inspector to inspect and debug the workers of interest, with a specific focus on associated wake locks, to align with the metric flagged in Android vitals. Investigation: Distinguishing between worker variants ** ** WHOOP uses both one-time and periodic scheduling for some workers. This allows the app to reuse the same Worker logic for identical tasks with the same success criteria, differing only in timing. ** ** Using their internal metrics made it possible to narrow their search to a specific worker, but they couldn't tell if the bug occurred when the worker was one-time, periodic, or both. So, they rolled out an update to use WorkManager’s setTraceTag method to distinguish between the one-time and periodic variants of the same Worker. ** ** This extra detail would allow them to definitively identify which Worker variant (periodic or one-time) was contributing the most to sessions with excessive partial wake locks. However, the team was surprised when the data revealed that neither variant appeared to be contributing more than the other. Manmeet Tuteja, Android Engineer II at WHOOP said “that split also helped us confirm the issue was happening in both variants, which pointed away from scheduling configuration and toward a shared business logic problem inside the worker implementation.” Diving deeper on worker behavior and fixing the root cause ** ** With the knowledge that they needed to take a look at logic within the worker,  the team re-examined worker behavior for the workers that had been flagged during their investigation. Specifically, they were looking for instances in which work may have been getting stuck and not completing. ** ** All of this culminated in finding the root cause of the excessive wake locks: ** ** A CoroutineWorker that was designed to wait for a connection to the WHOOP sensor before proceeding. ** ** If the work started with no sensor connected, whoopSensorFlow–which indicates if the sensor is connected– was null. The SensorWorker didn’t treat this as an early-exit condition and kept running, effectively waiting indefinitely for a connection. As a result, WorkManager held a partial wake lock until the work timed out, leading to high background wake lock usage and frequent, unwanted rescheduling of the SensorWorker. ** ** To address this, the WHOOP team updated the worker logic to check the connection status before attempting to execute the core business logic. If the sensor isn’t available, the worker exits, avoiding a timeout scenario and releasing the wake lock. The following code snippet shows the solution: class SensorWorker(appContext: Context, params: WorkerParameters): CoroutineWorker(appContext, params) { override suspend fun doWork(): Result { ... // Check the sensor state and perform work or return failure return whoopSensorFlow.replayCache .firstOrNull() ?.let { cachedData -> processSensorData(cachedData) Result.success() } ?: run { Result.failure() } } Achieving a 90% decrease in sessions with excessive partial wake locks ** ** After rolling out the fix, the team continued to monitor the Android vitals dashboard to confirm the impact of the changes. Ultimately, WHOOP saw their excessive partial wake lock percentage drop from 15% to less than 1% just 30 days after implementing the changes to their Worker. As a result of the changes, the team has seen fewer instances of work timing out without completing, resulting in lower average runtimes. The WHOOP team’s advice to other developers that want to improve their background work’s efficiency: Get Started If you’re interested in trying to reduce your app’s excessive partial wake locks or trying to improve worker efficiency, view your app’s excessive partial wake locks metric in Android vitals, and review the wake locks documentation for more best practices and debugging strategies.
04.03.2026 18:00 👍 0 🔁 0 💬 0 📌 0
Preview
A new era for choice and openness _ _Posted by  Sameer Samat, President of Android Ecosystem_ _ _ _ _ _ Android has always driven innovation in the industry through its unique flexibility and openness. At this important moment, we want to continue leading the way in how developers distribute their apps and games to people on billions of devices across many form factors. A modern platform must be flexible, providing developers and users with choice and openness as well as a safe experience. Today we are announcing substantial updates that evolve our business model and build on our long history of openness globally.  We’re doing that in three ways: more billing options, a program for registered app stores, and lower fees and new programs for developers. Expanded billing choice on Google Play for users and developers Google Play is giving developers even more billing choice and freedom in how they handle transactions. Mobile developers will have the option to use their own billing systems in their app alongside Google Play’s billing, or they can guide users outside of their app to their own websites for purchases. Our goal is to offer this flexibility in a way that maximizes choice and safety for users. Leading the way in store choice We’re introducing a program that makes sideloading qualified app stores even easier. Our new Registered App Stores program will provide a more streamlined installation flow for Android app stores that meet certain quality and safety benchmarks. Once this change has rolled out, app stores that choose to participate in this optional program will have registered with us and so users who sideload them will have a more simplified installation flow (see graphic below).  If a store chooses not to participate, nothing changes for them and they retain the same experience as any other sideloaded app on Android. This gives app stores more ways to reach users and gives users more ways to easily and safely access the apps and games they love. This Registered App Store program will begin outside of the US first, and we intend to bring it to the US as well, subject to court approval. Lower pricing and new programs to support developers Google Play’s fees are already the lowest among major app stores, and today we are taking this even further by introducing a new business model that decouples fees for using our billing system and introduces new, lower service fees. Once this rolls out: 1. Billing: For those developers who choose to use Google Play’s billing system, they will be charged a market-specific rate separate from the service fee. In the European Economic Area (EEA), UK, and US that rate will be 5%. 2. Service Fees: 1. For new installs (first time installs from users after the new fees are launched in a region), we are reducing the in-app purchase (IAP) service fee to 20%. 2. We are launching an Apps Experience Program and revamping our Google Play Games Level Up program to incentivize building great software experiences across Android form factors associated with clear quality benchmarks and enhanced user benefits.  Those developers who choose to participate in these programs will have even lower rates. Participating IAP developers will have a 20% service fee for transactions from existing installs and a 15% fee on transactions from new app installs. 3. Our service fee for recurring subscriptions will be 10%. Rollout timelines This is a significant evolution, and we plan to share additional details in the coming months. To make sure we have enough time to build the necessary technical infrastructure, enable a seamless transition for developers, and ensure alignment with local regulations, these updated fees will roll out on the following staggered schedule: * By June 30: EEA, the United Kingdom and the US. * By September 30: Australia * By December 31:  Korea and Japan * By September 30, 2027: The updates will reach the rest of the world. We will also launch the updated Google Play Games Level Up program and new App Experience program by September 30 for EEA, UK, US, and Australia and then it will roll out in line with the rest of the schedule above. We plan to launch Registered App Stores with a version of a major Android release by the end of the year. Resolving disputes with Epic Games With these updates, we have also resolved our disputes worldwide with Epic Games. We believe these changes will make for a stronger Android ecosystem with even more successful developers and higher-quality apps and games available across more form factors for everyone. We look forward to our continued work with the developer community to build the next generation of digital experiences.
04.03.2026 14:40 👍 0 🔁 0 💬 0 📌 0
Preview
Android devices extend seamlessly to connected displays _Posted by Francesco Romano, Senior Developer Relations Engineer on Android  _ We are excited to announce a major milestone in bringing mobile and desktop computing closer together on Android: connected display support has reached general availability with the Android 16 QPR3 release! As shown at Google I/O 2025, connected displays allow users to connect their Android devices to an external monitor and instantly access a desktop windowing environment. Apps can be used in free-form or maximized windows and users can multitask just like they would on a desktop OS. Google and Samsung have collaborated to bring a seamless and powerful desktop windowing experience to devices across the Android ecosystem running Android 16 while connected to an external display. This is now generally available on supported devices* to users who can connect their supported Pixel and Samsung phones to external monitors, enabling new opportunities for building more engaging and more productive app experiences that adapt across form factors. **How does it work?** When a supported Android phone or foldable is connected to an external display, a new desktop session starts on the connected display. The experience on the connected display is similar to the experience on a desktop, including a taskbar that shows active apps and lets users pin apps for quick access. Users are able to run multiple apps side by side simultaneously in freely resizable windows on the connected display. Phone connected to an external display with a desktop session on the display while the phone maintains its own state. When a device that supports desktop windowing (such as a tablet like the Samsung Galaxy Tab S11) is connected to an external display, the desktop session is extended across both displays, unlocking an even more expansive workspace. The two displays then function as one continuous system, allowing app windows, content, and the cursor to move freely between the displays. Tablet connected to an external display, extending the desktop session across both displays. ## Why does it matter? In the Android 16 QPR3 release, we finalized the windowing behaviors, taskbar interactions, and input compatibility (mouse and keyboard) that define the connected display experience. We also included compatibility treatments to scale windows and avoid app restarts when switching displays. If your app is built with adaptive design principles, it will automatically have the desktop look and feel, and users will feel right at home. If the app is locked to portrait or assumes a touch-only interface, now is the time to modernize. In particular, pay attention to these key best practices for optimal app experiences on connected displays: * Don't assume a constant Display object: The Display object associated with your app's context can change when an app window is moved to an external display or if the display configuration changes. Your app should gracefully handle configuration change events and query display metrics dynamically rather than caching them. * Account for density configuration changes: External displays can have vastly different pixel densities than the primary device screen. Ensure your layouts and resources adapt correctly to these changes to maintain UI clarity and usability. Use density-independent pixels (dp) for layouts, provide density-specific resources, and ensure your UI scales appropriately. * Correctly support external peripherals: When users connect to an external monitor, they often create a more desktop-like environment. This frequently involves using external keyboards, mice, trackpads, webcams, microphones, and speakers. Improve the support for keyboard and mouse interactions. **Building for the desktop future with modern tools** We provide several tools to help you build the desktop experience. Let’s recap the latest updates to our core adaptive libraries! **New window size classes: Large and Extra-large** The biggest update in Jetpack WindowManager 1.5.0 is the addition of two new width window size classes: Large and Extra-large. Window size classes are our official, opinionated set of viewport breakpoints that help you design and develop adaptive layouts. With 1.5.0, we're extending this guidance for screens that go beyond the size of typical tablets. Here are the new width breakpoints: * Large: For widths between 1200dp and 1600dp * Extra-large: For widths ≥1600dp The different window size classes based on display width. On very large surfaces, simply scaling up a tablet's Expanded layout isn't always the best user experience. An email client, for example, might comfortably show two panes (a mailbox and a message) in the Expanded window size class. But on an Extra-large desktop monitor, the email client could elegantly display three or even four panes, perhaps a mailbox, a message list, the full message content, and a calendar/tasks panel, all at once. To include the new window size classes in your project, simply call the function from the WindowSizeClass.BREAKPOINTS_V2 set instead of WindowSizeClass.BREAKPOINTS_V1: val currentWindowMetrics = WindowMetricsCalculator.getOrCreate() .computeCurrentWindowMetrics(LocalContext.current) val sizeClass = WindowSizeClass.BREAKPOINTS_V2 .computeWindowSizeClass(currentWindowMetrics) ** Then apply the correct layout when you’re sure your app has at least that much space: if(sizeClass.isWidthAtLeastBreakpoint( WindowSizeClass.WIDTH_DP_LARGE_LOWER_BOUND)){ ... // Window is at least 1200 dp wide. } ** ** Build adaptive layouts with Jetpack Navigation 3** Navigation 3 is the latest addition to the Jetpack collection. Navigation 3, which just reached its first stable release, is a powerful navigation library designed to work with Compose. Navigation 3 is also a great tool for building adaptive layouts by allowing multiple destinations to be displayed at the same time and allowing seamless switching between those layouts. This system for managing your app's UI flow is based on Scenes. A Scene is a layout that displays one or more destinations at the same time. A SceneStrategy determines whether it can create a Scene. Chaining SceneStrategy instances together allows you to create and display different scenes for different screen sizes and device configurations. For out-of-the-box canonical layouts, like list-detail and supporting pane, you can use the Scenes from the Compose Material 3 Adaptive library (available in version 1.3 and above). It's also easy to build your own custom Scenes by modifying the Scene recipes or starting from scratch. For example, let’s consider a Scene that displays three panes side by side: class ThreePaneScene<T : Any>( override val key: Any, override val previousEntries: List<NavEntry<T>>, val firstEntry: NavEntry<T>, val secondEntry: NavEntry<T>, val thirdEntry: NavEntry<T> ) : Scene<T> { override val entries: List<NavEntry<T>> = listOf(firstEntry, secondEntry, thirdEntry) override val content: @Composable (() -> Unit) = { Row(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.weight(1f)) { firstEntry.Content() } Column(modifier = Modifier.weight(1f)) { secondEntry.Content() } Column(modifier = Modifier.weight(1f)) { thirdEntry.Content() } } } In this scenario, you could define a SceneStrategy to show three panes if the window width is wide enough and the entries from your back stack have declared that they support being displayed in a three-pane scene. class ThreePaneSceneStrategy<T : Any>(val windowSizeClass: WindowSizeClass) : SceneStrategy<T> { override fun SceneStrategyScope<T>.calculateScene(entries: List<NavEntry<T>>): Scene<T>? { if (windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_LARGE_LOWER_BOUND)) { val lastThree = entries.takeLast(3) if (lastThree.size == 3 && lastThree.all { it.metadata.containsKey(MULTI_PANE_KEY) }) { val firstEntry = lastThree[0] val secondEntry = lastThree[1] val thirdEntry = lastThree[2] return ThreePaneScene( key = Triple(firstEntry.contentKey, secondEntry.contentKey, thirdEntry.contentKey), previousEntries = entries.dropLast(3), firstEntry = firstEntry, secondEntry = secondEntry, thirdEntry = thirdEntry ) } } return null } } You can use your ThreePaneSceneStrategy with other strategies when creating your NavDisplay. For example, we could also add a TwoPaneStrategy to display two panes side by side when there isn't enough space to show three. val strategy = ThreePaneSceneStrategy() then TwoPaneSceneStrategy() NavDisplay(..., sceneStrategy = strategy, entryProvider = entryProvider { entry<MyScreen>(metadata = mapOf(MULTI_PANE_KEY to true))) { ... } ... other entries... } ) If there isn't enough space to display three or two panes—both our custom scene strategies return null. In this case, NavDisplay falls back to displaying the last entry in the back stack in a single pane using SinglePaneScene. By using scenes and strategies, you can add one, two, and three pane layouts to your app!    An adaptive app showing three-pane navigation on wide screens. Checkout the documentation to learn more on how to create custom layouts using Scenes in Navigation 3. ### Standalone adaptive layouts If you need a standalone layout, the Compose Material 3 Adaptive library helps you create adaptive UIs like list-detail and supporting pane layouts that adapt themselves  to window configurations automatically based on  window size classes or device postures. The good news is that the library is already up to date with the new breakpoints! Starting from version 1.2, the default pane scaffold directive functions support Large and Extra-large width window size classes. You only need to opt-in by declaring in your Gradle build file that you want to use the new breakpoints: currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true) ### Getting started Explore the connected display feature in the latest Android release. Get Android 16 QPR3 on a supported device, then connect it to an external monitor to start testing your app today! Dive into the updated documentation on multi-display support and window management to learn more about implementing these best practices. Feedback Your feedback is crucial as we continue to refine the connected display desktop experience. Share your thoughts and report any issues through our official feedback channels. We're committed to making Android a versatile platform that adapts to the many ways users want to interact with their apps and devices. The improvements to connected display support are another step in that direction, and we think your users will love the desktop experiences you'll build! *Note: At the time the article is written, connected displays are supported on Pixel 8, 9, 10 series and on a wide array of Samsung devices, including S26, Fold7, Flip7, and Tab S11.
03.03.2026 18:00 👍 0 🔁 0 💬 0 📌 0
Preview
Go from prompt to working prototype with Android Studio Panda 2 _Posted by  __Matt Dyor, Senior Product Manager_ Android Studio Panda 2 is now stable and ready for you to use in production. This release brings new agentic capabilities to Android Studio, enabling the agent to create an entire working application from scratch with the AI-powered New Project flow, and allowing the agent to automate the manual work of dependency updates. Whether you're building your first prototype or maintaining a large, established codebase, these updates bring new efficiency to your workflow by enabling Gemini in Android Studio to help more than ever. Here’s a deep dive into what’s new: ## Create New Projects with AI Say goodbye to boilerplate starter templates that just get you to the start line. With the AI-powered New Project flow, you can now build a working app prototype with just a single prompt. The agent reduces the time you spend setting up dependencies, writing boilerplate code, and creating basic navigation, allowing you to focus on the creative aspects of app development. The AI-powered New Project flow allows you to describe exactly what you want to build - you can even upload images for style inspiration. The agent then creates a detailed project plan for your review. When you're ready, the agent turns your plan into a first draft of your app using Android best practices, including Kotlin, Compose, and the latest stable libraries. Under your direction, it creates an autonomous generation loop: it generates the necessary code, builds the project, analyzes any build errors, and attempts to self-correct the code, looping until your project builds successfully. It then deploys your app to an Android Emulator and walks through each screen, verifying that the implementation works correctly and is true to your original request. Whether you need a simple single-screen layout, a multi-page app with navigation, or even an application integrated with Gemini APIs, the AI-powered New Project flow can handle it. ### Getting Started To use the agent to set up a project, do the following: 1. Start Android Studio. 2. Select New Project on the Welcome to Android Studio screen (or File > New > New Project from within a project) 3. Select Create with AI. 4. Type your prompt into the text entry field and click Next.  For best results we recommend using a paid Gemini API key or third-party remote model. Create a New Project with AI in Android Studio > 5. Name your app and click Finish to start the generation process. > > 6. Validate the finished app using the project plan and by running your app in the Android Emulator or on an Android device. > > AI-powered New Project flow For more details on the New Project flow, check out the official documentation. ### Share What You Build We want to hear from you and see the apps you’re able to build using the New Project flow. Share your apps with us by using #AndroidStudio in your social posts. We’ll be amplifying some of your submissions on our social channels. ### Unlock more with your Gemini API key While the agent works out-of-the-box using Android Studio's default no-cost model, providing your own Google AI Studio API key unlocks the full potential of the assistant. By connecting a paid Gemini API key, you get access to the fastest and latest models from Google. It also allows the New Project flow to access Nano Banana, our best model for image generation, in order to ideate on UI design — allowing the agent to create richer, higher fidelity application designs. In the AI-powered New Project flow, this increased capability means larger context windows for more tailored generation, as well as superior code quality. Furthermore, because the Agent uses Nano Banana behind the scenes for enhanced design generation, your prototype doesn't just work well—it features visually appealing, modern UI layouts and looks professional from the get go. ## Version Upgrade Assistant Keeping your project dependencies up to date is time-consuming and often causes cascading build errors. You fix one issue by updating a dependency, only to introduce a new issue somewhere else. The Version Upgrade Assistant in Android Studio just made that a problem of the past. You can now let AI do the heavy lifting of managing dependencies and boilerplate so you can focus on creating unique experiences for your users. To use this feature, simply right-click in your version catalog, select AI, and then Update Dependencies. Version Upgrade Assistant accessed from Version Catalog You can also access the Version Upgrade Assistant from the Refactor menu—just choose Update all libraries with AI. Version Upgrade Assistant accessed from the Refactor menu The agent runs multiple automated rounds—attempting builds, reading error messages, and adjusting versions—until the build succeeds. Instead of manually fighting through dependency conflicts, you can let the agent handle the iterative process of finding a stable configuration for you. Read the documentation for more information on Version Upgrade Assistant. ## Gemini 3.1 Pro is available in Android Studio We released Gemini 3.1 Pro preview, and it is even better than Gemini 3 Pro for reasoning and intelligence. You can access it in Android Studio by plugging in your Gemini API key. Put the new model to work on your toughest bugs, code completion, and UI logic. Let us know what you think of the new model. Gemini 3.1 Pro Now Available in Android Studio ## Get started Dive in and accelerate your development. Download Android Studio Panda 2 Feature Drop and start exploring these powerful new agentic features today. As always, your feedback is crucial to us. Check known issues, report bugs, and be part of our vibrant community on LinkedIn, Medium, YouTube, or X. Happy coding!
03.03.2026 14:00 👍 0 🔁 0 💬 0 📌 0
Preview
Supercharge your Android development with 6 expert tips for Gemini in Android Studio __ _Posted by  Trevor Johns, Developer Relations Engineer_ __ _ _ _ _ _ _ _ _ _ _ In January we announced Android Studio Otter 3 Feature Drop in stable, including Agent Mode enhancements and many other updates to provide more control and flexibility over using AI to help you build high quality Android apps. To help you get the most out of Gemini in Android Studio and all the new capabilities, we sat down with Google engineers and Google Developer Experts to gather their best practices for working with the latest features—including Agent mode and the New Project Assistant. Here are some useful insights to help you get the best out of your development: 1. Build apps from scratch with the New Project Assistant The new Project Assistant—now available in the latest Canary builds—integrates Gemini with the Studio's New Project wizard. By simply providing prompts and (optionally) design mockups, you can generate entire applications from scratch, including scaffolding, architecture, and Jetpack Compose layouts. Integrated with the Android Emulator, it can deploy your build and "walk through" the app, making sure it’s functioning correctly and that the rendered screens actually match your vision. Additionally, you can use Agent Mode to then continue to work on the app and iterate, leveraging Gemini to refine your app to fit your vision. Also, while this feature works with the default (no-cost) model, we highly recommend using this feature with an AI Studio API Key to access the latest models — like Gemini 3.1 Pro or 3.0 Flash — which excel at agentic workflows. Additionally, adding your API Key allows the New Project Assistant to use Nano Banana behind the scenes to help with ideating on UI design, improving the visual fidelity of the generated application! - Trevor Johns, Developer Relations Engineer. Dialog for setting up a new project. 2. Ask the Agent to refine your code by providing it with ‘intentional’ contexts When using Gemini Agents, the quality of the output is directly tied to the boundaries you set. Don't just ask it to "fix this code"— be very intentional with the context that you provide it and be specific about what you want (and what you don't). Improve the output by providing recent blogs or docs so the model can make accurate suggestions based on these. Ask the Agent to simplify complex logic, or if it see’s any fundamental problems with it, or even ask it to scan for security risks in areas where you feel uncertain. Being firm with your instructions—even telling the model "please do not invent things" in instances where you are using very new or experimental APIs—helps keep the AI focused on the outputs you are trying to achieve. - Alejandra Stamato, Android Google Developer Expert and Android Engineer at HubSpot. ** ** 3. Use documentation with Agent mode to provide context for new libraries ** ** To prevent the model from hallucinating code for niche or brand-new libraries, leverage Android Studio’s Agent tools, to have access to documentation: Search Android Docs and Fetch Android Docs. You can direct Gemini to search the Android Knowledge Base or specific documentation articles. The model can choose to use this if it thinks it’s missing some information, which is good especially when you use niche API’s, or one’s which aren’t as common. ** ** If you are certain you want the model to consult the documentation and to make sure those tools are triggered, a good trick is to add something like ‘search the official documentation’ or ‘check the docs’ to your prompts. And for documentation on different libraries which aren’t Android specific, install a MCP Server that lets you access documentation like Context7 (or something similar). - Jose Alcérreca, Android Developer Relations Engineer, Google. ** ** 4. Use AI to help build Agents.md files for using custom frameworks, libraries and design systems To make sure Agent uses custom frameworks, libraries and design systems you have two options 1) In settings, Android Studio allows you to specify rules to be followed when Gemini is performing these actions for you. Or 2) Create Agents.md files in your application and specify how things should be done or act as guidance for when AI is performing a task, specific frameworks, design systems, or specific ways of doing things (such as the exact architecture, things to do or what not to do), in a standard bullet point way to give AI clear instructions. Manage AGENTS.md files as context. You can also use Agents.md file at the root of the project, and can have them in different modules (or even subdirectories) of your project as well! The more context you have or the more guidance available when you’re working, that will be available for AI to access. If you get stuck creating these Agents.md files you can use AI to help build them, or give you foundations based on the projects you have and then edit them so you don’t have to start from scratch. - Joe Birch, Android Google Developer Expert and Staff Engineer at Buffer. 5. Offload the tedious tasks to Agent and save yourself time You can get Gemini in Android Studio agent to help you make tasks such as writing and reviewing faster. For example it can help writing commit messages, giving you a good summary which you can then review and save yourself time. Additionally, get it to write tests; under your direction the Agent can look at the other tests in your project and write a good test for you to run following best practices just by looking at them. Another good example of a tedious task is writing a new parser for a certain JSON format. Just give Gemini a few examples and it will get you started very quickly. - Diego Perez, Android Software Engineer, Google ** ** 6. Control what you are sharing with AI using simple opt-outs or commands, alongside paid models. If you want to control what is shared with AI whilst on the no-cost plans, you can opt out some or all your code from model training by adding an AI exclusions file (‘.aiexclude’) to your project. This file uses glob pattern matching similar to a .gitignore file, specifying sensitive directories or files that should be hidden from the AI. You can place .aiexclude files anywhere within the project and its VCS roots to control which files AI features are allowed to access. An example of an `.aiexclude` file in Android Studio. Alternatively, in Android Studio settings, you can also opt out of context sharing either on a per project or per user basis (although this method limits the functionality of a number of features because the AI won’t see your code). Remember, paid plans never use your code for model training. This includes both users using an AI Studio API Key, and businesses who are subscribed to Gemini Code Assist. - Trevor Johns, Developer Relations Engineer. Hear more from the Android team and Google Developer Experts about Gemini in Android Studio in our recent fireside chat and download Android Studio to get started.
02.03.2026 14:00 👍 0 🔁 0 💬 0 📌 0
Preview
Preventing accessibility permission abuse in the Android ecosystem _Posted by Bethel Otuteye - Senior Director, Product Management, Android App Safety_ Security is a foundational pillar of Android, we continually work on ways to make the platform safer for everyone. This release builds on our ongoing efforts, which include a range of APIs and features designed to help developers protect user data and fight against malware. From Credential Manager for a streamlined and more secure sign-in experience to resources on Preventing Fraudulent Activity, we're consistently working to identify and close potential vulnerabilities. We know that a strong security posture requires collaboration across the entire ecosystem. It's a joint effort between us and the developer community to create a more secure experience for everyone. ### Protecting your apps from snooping with a single line of code To further enhance user security, Android is continually evolving its defenses against malicious apps that attempt to abuse the Accessibility API's powerful features. The abuse includes reading sensitive information, such as passwords and financial details, directly from the screen and even manipulating a user's device by injecting touches. To combat this, we have a feature in Android 16 that gives you a powerful tool to prevent this type of abuse with a single line of code. The accessibilityDataSensitive flag allows you to explicitly mark a view or composable as containing sensitive data. When this flag is set to true,  apps with the accessibility permission that have not explicitly set the isAccessibilityTool to ‘true’ (isAccessibilityTool=true) are blocked from accessing the view's data or performing interactions on it. This simple but effective change helps to prevent malware from stealing information and performing unauthorized actions, without impacting the functionality of legitimate accessibility tools. Note: If an app is not an accessibility tool but requests accessibility permissions and sets isAccessibilityTool=true, it will be rejected on Play and will be blocked by Play Protect on user devices. As an added benefit for developers, we've integrated this new functionality with the existing setFilterTouchesWhenObscured method. If you're already using setFilterTouchesWhenObscured(true) to protect against touchjacking, your views will automatically be treated as sensitive data for accessibility. This ensures that a large portion of the developer community will immediately benefit from this security enhancement. ### Getting started We encourage you to use the setFilterTouchesWhenObscured (recommended) or the accessibilityDataSensitive flag on any screen that contains sensitive information, including login pages, payment flows, and any view displaying personal or financial data. #### For Jetpack Compose ### ** setFilterTouchesWhenObscured| accessibilityDataSensitive ---|--- val composeView = LocalView.current DisposableEffect(Unit) { composeView.filterTouchesWhenObscured = true onDispose { composeView.filterTouchesWhenObscured = false } } | Use the semantics modifier to apply the sensitiveData property to a composable.BasicText { text = “Your password”,            modifier = Modifier.semantics {                sensitiveData = true }} ** #### For View-based apps In your XML layout, add the relevant attribute to the sensitive view. ### setFilterTouchesWhenObscured| accessibilityDataSensitive ---|--- <TextView android:filterTouchesWhenObscured="true" /> | <TextView android:accessibilityDataSensitive="true" /> ### ### Alternatively, you can set the property programmatically in Java or Kotlin: ### setFilterTouchesWhenObscured| accessibilityDataSensitive ---|--- myView.filterTouchesWhenObscured = true; | myView.isAccessibilityDataSensitive = true; myView.setFilterTouchesWhenObscured(true) | myView.setAccessibilityDataSensitive(true); You can read more about the accessibilityDataSensitive and setFilterTouchesWhenObscured flags in the Tapjacking guide. ### Partnering with developers to keep users safe We've been working with developers from the start to ensure this feature meets their needs, and we're already hearing great feedback. ### "We've always prioritized protecting our customers' sensitive financial data, which required us to build our own protection layer against accessibility-based malware. Revolut strongly supports the introduction of this new, official Android API, as it allows us to gradually move away from our custom code in favor of a robust, single-line platform defense." - Vladimir Kozhevnikov, Android Engineer at Revolut We believe these new tools represent a significant step forward in our mission to make Android a safer platform for everyone. By leveraging setFilterTouchesWhenObscured or adopting accessibilityDataSensitive, you can play a crucial role in protecting your users from malicious accessibility-based attacks. We encourage all developers to integrate these features into their apps to strengthen the security of the Android ecosystem as a whole. Together, we can build a more secure and trustworthy experience for all Android users.
28.02.2026 17:00 👍 2 🔁 0 💬 0 📌 0
Preview
Spotlight Week: Android Safety and Security _Posted by Todd Burner - Android Developer Relations_ ## Announcing our Safety and Security Spotlight Week! This week, we’re launching our first-ever Spotlight Week dedicated to Android Safety and Security. To kick things off, we’re excited to announce the launch of early access for the new Android developer verification experience. The first few invites are rolling out soon and you can still sign up today. This program is a foundational step in our commitment to elevate Android security and make the ecosystem safer for everyone. The Safety and Security Spotlight Week will provide resources—blog posts, videos, and more—all designed to help you build more secure apps and prepare for upcoming changes. Here’s what’s coming: * Android developer verification (Tuesday, November 11th): We’re kicking off the week with a deep dive into the new Android developer verification requirements. We’ll explain what they are, how to get ready, and a preview of the new Android Developer Console. * Learn more in the deep-dive blog post. * Watch the video. * Play Integrity API - stronger threat detection, simpler integration (Wednesday, November 12th): Learn how to better protect your apps and games from abuse and attack with the Play Integrity API. We’ll cover use cases and recommended practices, and introduce the new in-app remediation prompts that help users resolve integrity issues and API error codes automatically. * Accessibility APIs (Thursday, November 13th): We’ll cover how adding just one line to your code with the isAccessibilityDataSentitive flag, can protect your user’s sensitive information and prevent abuse of the Android accessibility APIs. * Cyber Security Awareness with Advanced Protection Mode (Thursday, November 13th): Advanced Protection offers greater security functionality for Android’s most sensitive users by allowing them to make changes to device protection settings across Android through one simple toggle. That’s a look at what we’ll be covering during our Safety and Security Spotlight Week. Be sure to check back here throughout the week, as we’ll be updating this post with all the latest links. Follow the Android Developers channels on X and LinkedIn to get the latest updates as they happen.
28.02.2026 17:00 👍 2 🔁 0 💬 0 📌 0
Preview
The Second Beta of Android 17 _Posted by Matthew McCullough, VP Product Management, Android Developer_ Today we're releasing the second beta of Android 17, continuing our work to build a platform that prioritizes privacy, security, and refined performance. This update delivers a range of new capabilities, including the EyeDropper API and a privacy-preserving Contacts Picker. We're also adding advanced ranging, cross-device handoff APIs, and more. This release continues the shift in our release cadence, following this annual major SDK release in Q2 with a minor SDK update. ## User Experience & System UI ### Bubbles Bubbles is a windowing mode feature that offers a new floating UI experience separate from the messaging bubbles API. Users can create an app bubble on their phone, foldable, or tablet by long-pressing an app icon on the launcher. On large screens, there is a bubble bar as part of the taskbar where users can organize, move between, and move bubbles to and from anchored points on the screen. You should follow the guidelines for supporting multi-window mode to ensure your apps work correctly as bubbles. EyeDropper API A new system-level EyeDropper API allows your app to request a color from any pixel on the display without requiring sensitive screen capture permissions. val eyeDropperLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { val color = result.data?.getIntExtra(Intent.EXTRA_COLOR, Color.BLACK) // Use the picked color in your app } } fun launchColorPicker() { val intent = Intent(Intent.ACTION_OPEN_EYE_DROPPER) eyeDropperLauncher.launch(intent) } ### Contacts Picker A new system-level contacts picker via ACTION_PICK_CONTACTS grants temporary, session-based read access to only the specific data fields requested by the user, reducing the need for the broad READ_CONTACTS permissions. It also allows for selections from the device’s personal or work profiles. val contactPicker = rememberLauncherForActivityResult(StartActivityForResult()) { if (it.resultCode == RESULT_OK) { val uri = it.data?.data ?: return@rememberLauncherForActivityResult // Handle result logic processContactPickerResults(uri) } } val dataFields = arrayListOf(Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE) val intent = Intent(ACTION_PICK_CONTACTS).apply { putStringArrayListExtra(EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS, dataFields) putExtra(EXTRA_ALLOW_MULTIPLE, true) putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5) } contactPicker.launch(intent) ### Easier pointer capture compatibility with touchpads Previously, touchpads reported events in a very different way from mice when an app had captured the pointer, reporting the locations of fingers on the pad rather than the relative movements that would be reported by a mouse. This made it quite difficult to support touchpads properly in first-person games. Now, by default the system will recognize pointer movement and scrolling gestures when the touchpad is captured, and report them just like mouse events. You can still request the old, detailed finger location data by explicitly requesting capture in the new “absolute” mode. // To request the new default relative mode (mouse-like events) // This is the same as requesting with View.POINTER_CAPTURE_MODE_RELATIVE view.requestPointerCapture() // To request the legacy absolute mode (raw touch coordinates) view.requestPointerCapture(View.POINTER_CAPTURE_MODE_ABSOLUTE) **Interactive Chooser resting bounds** By calling getInitialRestingBounds on Android's ChooserSession, your app can identify the target position the Chooser occupies after animations and data loading are complete, enabling better UI adjustments. ## Connectivity & Cross-Device ### Cross-device app handoff A new Handoff API allows you to specify application state to be resumed on another device, such as an Android tablet. When opted in, the system synchronizes state via CompanionDeviceManager and displays a handoff suggestion in the launcher of the user's nearby devices. This feature is designed to offer seamless task continuity, enabling users to pick up exactly where they left off in their workflow across their Android ecosystem. Critically, Handoff supports both native app-to-app transitions and app-to-web fallback, providing maximum flexibility and ensuring a complete experience even if the native app is not installed on the receiving device. ### Advanced ranging APIs We are adding support for 2 new ranging technologies - 1. UWB DL-TDOA which enables apps to use UWB for indoor navigation. This API surface is FIRA (Fine Ranging Consortium) 4.0 DL-TDOA spec compliant and enables privacy preserving indoor navigation  (avoiding tracking of the device by the anchor). 2. Proximity Detection which enables apps to use the new ranging specification being adopted by WFA (WiFi Alliance). This technology provides improved reliability and accuracy compared to existing Wifi Aware based ranging specification. ### Data plan enhancements To optimize media quality, your app can now retrieve carrier-allocated maximum data rates for streaming applications using getStreamingAppMaxDownlinkKbps and getStreamingAppMaxUplinkKbps. ## Core Functionality, Privacy & Performance ### Local Network Access Android 17 introduces the ACCESS_LOCAL_NETWORK runtime permission to protect users from unauthorized local network access. Because this falls under the existing NEARBY_DEVICES permission group, users who have already granted other NEARBY_DEVICES permissions will not be prompted again. By declaring and requesting this permission, your app can discover and connect to devices on the local area network (LAN), such as smart home devices or casting receivers. This prevents malicious apps from exploiting unrestricted local network access for covert user tracking and fingerprinting. Apps targeting Android 17 or higher will now have two paths to maintain communication with LAN devices: adopt system-mediated, privacy-preserving device pickers to skip the permission prompt, or explicitly request this new permission at runtime to maintain local network communication. ### Time zone offset change broadcast Android now provides a reliable broadcast intent, ACTION_TIMEZONE_OFFSET_CHANGED, triggered when the system's time zone offset changes, such as during Daylight Saving Time transitions. This complements the existing broadcast intents ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED, which are triggered when the Unix timestamp changes and when the time zone ID changes, respectively. ### NPU Management and Prioritization Apps targeting Android 17 that need to directly access the NPU must declare FEATURE_NEURAL_PROCESSING_UNIT in their manifest to avoid being blocked from accessing the NPU. This includes apps that use the LiteRT NPU delegate, vendor-specific SDKs, as well as the deprecated NNAPI. **ICU 78 and Unicode 17 support** Core internationalization libraries have been updated to ICU 78, expanding support for new scripts, characters, and emoji blocks, and enabling direct formatting of time objects. ### SMS OTP protection Android is expanding its SMS OTP protection by automatically delaying access to SMS messages with OTP. Previously, the protection was primarily focused on the SMS Retriever format wherein the delivery of messages containing an SMS retriever hash is delayed for most apps for three hours. However, for certain apps like the default SMS app, etc and the app that corresponds to the hash are exempt from this delay. This update extends the protection to all SMS messages with OTP. For most apps, SMS messages containing an OTP will only be accessible after a delay of three hours to help prevent OTP hijacking. The SMS_RECEIVED_ACTION broadcast will be withheld and sms provider database queries will be filtered. The SMS message will be available to these apps after the delay. **Delayed access to WebOTP format SMS messages** If the app has the permission to read SMS messages but is not the intended recipient of the OTP (as determined by domain verification), the WebOTP format SMS message will only be accessible after three hours have elapsed. This change is designed to improve user security by ensuring that only apps associated with the domain mentioned in the message can programmatically read the verification code. This change applies to all apps regardless of their target API level. **Delayed access to standard SMS messages with OTP** For SMS messages containing an OTP that do not use the WebOTP or SMS Retriever formats, the OTP SMS will only be accessible after three hours for most apps. This change only applies to apps that target Android 17 (API level 37) or higher. Certain apps such as the default SMS, assistant app, along with connected device companion apps, etc will be exempt from this delay. All apps that rely on reading SMS messages for OTP extraction should transition to using SMS Retriever or SMS User Consent APIs to ensure continued functionality. ## The Android 17 schedule We're going to be moving quickly from this Beta to our Platform Stability milestone, targeted for March. At this milestone, we'll deliver final SDK/NDK APIs. From that time forward, your app can target SDK 37 and publish to Google Play to help you complete your testing and collect user feedback in the several months before the general availability of Android 17. ### A year of releases We plan for Android 17 to continue to get updates in a series of quarterly releases. The upcoming release in Q2 is the only one where we introduce planned app breaking behavior changes. We plan to have a minor SDK release in Q4 with additional APIs and features. ## Get started with Android 17 You can enroll any supported Pixel device to get this and future Android Beta updates over-the-air. If you don’t have a Pixel device, you can use the 64-bit system images with the Android Emulator in Android Studio. If you are currently in the Android Beta program, you will be offered an over-the-air update to Beta 2. If you have Android 26Q1 Beta and would like to take the final stable release of 26Q1 and exit Beta, you need to ignore the over-the-air update to 26Q2 Beta 2 and wait for the release of 26Q1. We're looking for your feedback so please report issues and submit feature requests on the feedback page. The earlier we get your feedback, the more we can include in our work on the final release. For the best development experience with Android 17, we recommend that you use the latest preview of Android Studio (Panda). Once you’re set up, here are some of the things you should do: * Compile against the new SDK, test in CI environments, and report any issues in our tracker on the feedback page. * Test your current app for compatibility, learn whether your app is affected by changes in Android 17, and install your app onto a device or emulator running Android 17 and extensively test it. We’ll update the preview/beta system images and SDK regularly throughout the Android 17 release cycle. Once you’ve installed a beta build, you’ll automatically get future updates over-the-air for all later previews and Betas. For complete information, visit the Android 17 developer site. ### Join the conversation As we move toward Platform Stability and the general availability of Android 17 later this year, your feedback remains our most valuable asset. Whether you’re an early adopter on   the Canary channel or an app developer testing on Beta 2, consider joining our communities and filing feedback. We’re listening.
26.02.2026 21:08 👍 0 🔁 0 💬 0 📌 0
Preview
The Intelligent OS: Making AI agents more helpful for Android apps _Posted by Matthew McCullough, VP of Product Management, Android Development_ User expectations for AI on their devices are fundamentally shifting how they interact with their apps. Instead of opening apps to do tasks step-by-step, they're asking AI to do the heavy lifting for them. In this new interaction model, success is shifting from getting users to open your app, to successfully fulfilling their tasks and helping them get more done faster. To help you evolve your apps for this agentic future, we're introducing early stage developer capabilities that bridge the gap between your apps and agentic apps and personalized assistants, such as Google Gemini. While we are in the early, beta stages of this journey, we’re designing these features with privacy and security at their core as our first step in exploring this paradigm shift as an app ecosystem. Empowering apps with AppFunctions Android AppFunctions allows apps to expose data and functionality directly to AI agents and assistants. With the AppFunctions Jetpack library and platform APIs, developers can create self-describing functions that agentic apps can discover and execute via natural language. Mirroring how backend capabilities are declared via MCP cloud servers, AppFunctions provides an on-device solution for Android apps. Much like WebMCP, it executes these functions locally on the device rather than on a server. The Samsung Gallery integration with Gemini on the Galaxy S26 series showcases AppFunctions in action. Instead of manually scrolling through photo albums, you can now simply ask Gemini to "Show me pictures of my cat from Samsung Gallery." Gemini takes the user query, intelligently identifies and triggers the right function, and presents the returned photos from Samsung Gallery directly in the Gemini app, so users never need to leave. This experience is multimodal and can be done via voice or text. Users can even use the returned photos in follow-up conversations, like sending them to friends in a text message. This integration is currently available on the Galaxy S26 series and will soon expand to Samsung devices running OneUI 8.5 and higher. Through AppFunctions, Gemini can already automate tasks across app categories like Calendar, Notes, and Tasks, on devices from multiple manufacturers. Whether it’s coordinating calendar events, organizing notes, or setting to-do reminders, users can streamline daily activities in one place. Enabling agentic apps with intelligent UI automation While AppFunctions provides a structured framework and more control for apps to communicate with AI agents and assistants, we know that not every interaction has a dedicated integration yet. We’re also developing a UI automation framework for AI agents and assistants to intelligently execute generic tasks on users’ installed apps, with user transparency and control built in. This is the platform doing the heavy lifting, so developers can get agentic reach with zero code. It’s a low-effort way to extend their reach without a major engineering lift right now. To get feedback as we refine this framework, we’re starting with an early preview on the Galaxy S26 series and select Pixel 10 devices, where users will be able to delegate multi-step tasks to Gemini with just a long press of the power button. Launching as a beta feature in the Gemini app, this will support a curated selection of apps in the food delivery, grocery, and rideshare categories in the US and Korea to start. Whether users need to place a complex pizza order for their family members with particular tastes, coordinate a multi-stop rideshare with co-workers, or reorder their last grocery purchase, Gemini can help complete tasks using the context already available from your apps, without any developer work needed. Users are in control while a task is being actioned in the background through UI automation. For any automation action, users have the option to monitor a task’s progress via notifications or "live view" and can switch to manual control at any point to take over the experience. Gemini is also designed to alert users before completing sensitive tasks, such as making a purchase. Looking ahead In Android 17, we’re looking to broaden these capabilities to reach even more users, developers, and device manufacturers. We are currently building experiences with a small set of app developers, focusing on high-quality user experiences as the ecosystem evolves. We plan to share more details later this year on how you can use AppFunctions and UI automation to enable agentic integrations for your app. Stay tuned for updates.
25.02.2026 23:47 👍 1 🔁 0 💬 0 📌 0
Preview
Get ready for Google I/O May 19-20 _Posted by The Google I/O Team_ Google I/O returns May 19–20 Google I/O is back! Join us online as we share our latest AI breakthroughs and updates in products across the company, from Gemini to Android, Chrome, Cloud, and more. Tune in to learn about agentic coding and the latest Gemini model updates. The event will feature keynote addresses from Google leaders, forward-looking panel discussions, and product demos designed to showcase the next frontier of technology. Register now and tune in live Visit io.google and register to receive updates about Google I/O. Kicking off May 19 at 10am PT, this year we’ll be livestreaming keynotes, demos, and more sessions across two days. We’ll also be bringing back the popular Dialogues sessions featuring big thinkers and bold leaders discussing how AI is shaping our future.
17.02.2026 20:00 👍 0 🔁 0 💬 0 📌 0
Preview
Under the hood: Android 17’s lock-free MessageQueue _Posted by Shai Barack, Android Platform Performance Lead and Charles Munger, Principal Software Engineer_ In Android 17, apps targeting SDK 37 or higher will receive a new implementation of MessageQueue where the implementation is lock-free. The new implementation improves performance and reduces missed frames, but may break clients that reflect on MessageQueue private fields and methods. To learn more about the behavior change and how you can mitigate impact, check out the MessageQueue behavior change documentation. This technical blog post provides an overview of the MessageQueue rearchitecture and how you can analyze lock contention issues using Perfetto. The Looper drives the UI thread of every Android application. It pulls work from a MessageQueue, dispatches it to a Handler, and repeats. For two decades, MessageQueue used a single monitor lock (i.e. a synchronized code block) to protect its state. Android 17 introduces a significant update to this component: a lock-free implementation named DeliQueue. This post explains how locks affect UI performance, how to analyze these issues with Perfetto, and the specific algorithms and optimizations used to improve the Android main thread. The problem: Lock Contention and Priority Inversion The legacy MessageQueue functioned as a priority queue protected by a single lock. If a background thread posts a message while the main thread performs queue maintenance, the background thread blocks the main thread. When two or more threads are competing for exclusive use of the same lock, this is called Lock contention. This contention can cause Priority Inversion, leading to UI jank and other performance problems. Priority inversion can happen when a high-priority thread (like the UI thread) is made to wait for a low-priority thread. Consider this sequence: 1. A low priority background thread acquires the MessageQueue lock to post the result of work that it did. 2. A medium priority thread becomes runnable and the Kernel's scheduler allocates it CPU time, preempting the low priority thread. 3. The high priority UI thread finishes its current task and attempts to read from the queue, but is blocked because the low priority thread holds the lock. The low-priority thread blocks the UI thread, and the medium-priority work delays it further. Analyzing contention with Perfetto You can diagnose these issues using Perfetto. In a standard trace, a thread blocked on a monitor lock enters the sleeping state, and Perfetto shows a slice indicating the lock owner. When you query trace data, look for slices named “monitor contention with …” followed by the name of the thread that owns the lock and the code site where the lock was acquired. Case study: Launcher jank To illustrate, let’s analyze a trace where a user experienced jank while navigating home on a Pixel phone immediately after taking a photo in the camera app. Below we see a screenshot of Perfetto showing the events leading up to the missed frame: * Symptom: The Launcher main thread missed its frame deadline. It blocked for 18ms, which exceeds the 16ms deadline required for 60Hz rendering. * Diagnosis: Perfetto showed the main thread blocked on the MessageQueue lock. A “BackgroundExecutor” thread owned the lock. * Root Cause: The BackgroundExecutor runs at Process.THREAD_PRIORITY_BACKGROUND (very low priority). It performed a non-urgent task (checking app usage limits). Simultaneously, medium priority threads were using CPU time to process data from the camera. The OS scheduler preempted the BackgroundExecutor thread to run the camera threads. This sequence caused the Launcher’s UI thread (high priority) to become indirectly blocked by the camera worker thread (medium priority), which was keeping the Launcher’s background thread (low priority) from releasing the lock. Querying traces with PerfettoSQL You can use PerfettoSQL to query trace data for specific patterns. This is useful if you have a large bank of traces from user devices or tests, and you’re searching for specific traces that demonstrate a problem. For example, this query finds MessageQueue contention coincident with dropped frames (jank): INCLUDE PERFETTO MODULE android.monitor_contention; INCLUDE PERFETTO MODULE android.frames.jank_type; SELECT process_name, -- Convert duration from nanoseconds to milliseconds SUM(dur) / 1000000 AS sum_dur_ms, COUNT(*) AS count_contention FROM android_monitor_contention WHERE is_blocked_thread_main AND short_blocked_method LIKE "%MessageQueue%" -- Only look at app processes that had jank AND upid IN ( SELECT DISTINCT(upid) FROM actual_frame_timeline_slice WHERE android_is_app_jank_type(jank_type) = TRUE ) GROUP BY process_name ORDER BY SUM(dur) DESC; In this more complex examples, join trace data that spans multiple tables to identify MessageQueue contention during app startup: INCLUDE PERFETTO MODULE android.monitor_contention; INCLUDE PERFETTO MODULE android.startup.startups; -- Join package and process information for startups DROP VIEW IF EXISTS startups; CREATE VIEW startups AS SELECT startup_id, ts, dur, upid FROM android_startups JOIN android_startup_processes USING(startup_id); -- Intersect monitor contention with startups in the same process. DROP TABLE IF EXISTS monitor_contention_during_startup; CREATE VIRTUAL TABLE monitor_contention_during_startup USING SPAN_JOIN(android_monitor_contention PARTITIONED upid, startups PARTITIONED upid); SELECT process_name, SUM(dur) / 1000000 AS sum_dur_ms, COUNT(*) AS count_contention FROM monitor_contention_during_startup WHERE is_blocked_thread_main AND short_blocked_method LIKE "%MessageQueue%" GROUP BY process_name ORDER BY SUM(dur) DESC; You can use your favorite LLM to write PerfettoSQL queries to find other patterns. At Google, we use BigTrace to run PerfettoSQL queries across millions of traces. In doing so, we confirmed that what we saw anecdotally was, in fact, a systemic issue. The data revealed that MessageQueue lock contention impacts users across the entire ecosystem, substantiating the need for a fundamental architectural change. Solution: lock-free concurrency We addressed the MessageQueue contention problem by implementing a lock-free data structure, using atomic memory operations rather than exclusive locks to synchronize access to shared state. A data structure or algorithm is lock-free if at least one thread can always make progress regardless of the scheduling behavior of the other threads. This property is generally hard to achieve, and is usually not worth pursuing for most code. The atomic primitives Lock-free software often relies on atomic Read-Modify-Write primitives that the hardware provides. On older generation ARM64 CPUs, atomics used a Load-Link/Store-Conditional (LL/SC) loop. The CPU loads a value and marks the address. If another thread writes to that address, the store fails, and the loop retries. Because the threads can keep trying and succeed without waiting for another thread, this operation is lock-free. ARM64 LL/SC loop example retry: ldxr x0, [x1] // Load exclusive from address x1 to x0 add x0, x0, #1 // Increment value by 1 stxr w2, x0, [x1] // Store exclusive. // w2 gets 0 on success, 1 on failure cbnz w2, retry // If w2 is non-zero (failed), branch to retr (view in Compiler Explorer) Newer ARM architectures (ARMv8.1) support Large System Extensions (LSE) which include instructions in the form of Compare-And-Swap (CAS) or Load-And-Add (demonstrated below). In Android 17 we added support to the Android Runtime (ART) compiler to detect when LSE is supported and emit optimized instructions: / ARMv8.1 LSE atomic example ldadd x0, x1, [x2] // Atomic load-add. // Faster, no loop required. In our benchmarks, high-contention code that uses CAS achieves a ~3x speedup over the LL/SC variant. The Java programming language offers atomic primitives via java.util.concurrent.atomic that rely on these and other specialized CPU instructions. The Data Structure: DeliQueue To remove lock contention from MessageQueue, our engineers designed a novel data structure called DeliQueue. DeliQueue separates Message insertion from Message processing: 1. The list of Messages (Treiber stack): A lock-free stack. Any thread can push new Messages here without contention. 2. The priority queue (Min-heap): A heap of Messages to handle, exclusively owned by the Looper thread (hence no synchronization or locks are needed to access). ### Enqueue: pushing to a Treiber stack The list of Messages is kept in a Treiber stack [1], a lock-free stack that uses a CAS loop to update the head pointer. public class TreiberStack <E> { AtomicReference<Node<E>> top = new AtomicReference<Node<E>>(); public void push(E item) { Node<E> newHead = new Node<E>(item); Node<E> oldHead; do { oldHead = top.get(); newHead.next = oldHead; } while (!top.compareAndSet(oldHead, newHead)); } public E pop() { Node<E> oldHead; Node<E> newHead; do { oldHead = top.get(); if (oldHead == null) return null; newHead = oldHead.next; } while (!top.compareAndSet(oldHead, newHead)); return oldHead.item; } } Source code based on Java Concurrency in Practice 2], [available online and released to the public domain Any producer can push new Messages to the stack at any time. This is like pulling a ticket at a deli counter - your number is determined by when you showed up, but the order you get your food in doesn't have to match. Because it's a linked stack, every Message is a sub-stack - you can see what the Message queue was like at any point in time by tracking the head and iterating forwards - you won't see any new Messages pushed on top, even if they're being added during your traversal. ### Dequeue: bulk transfer to a min-heap To find the next Message to handle, the Looper processes new Messages from the Treiber stack by walking the stack starting from the top and iterating until it finds the last Message that it previously processed. As the Looper traverses down the stack, it inserts Messages into the deadline-ordered min-heap. Since the Looper exclusively owns the heap, it orders and processes Messages without locks or atomics. In walking down the stack, the Looper also creates links from stacked Messages back to their predecessors, thus forming a doubly-linked list. Creating the linked list is safe because links pointing down the stack are added via the Treiber stack algorithm with CAS, and links up the stack are only ever read and modified by the Looper thread. These back links are then used to remove Messages from arbitrary points in the stack in O(1) time. This design provides _O_(1) insertion for producers (threads posting work to the queue) and amortized _O_(log N) processing for the consumer (the Looper). Using a min-heap to order Messages also addresses a fundamental flaw in the legacy MessageQueue, where Messages were kept in a singly-linked list (rooted at the top). In the legacy implementation, removal from the head was _O_(1), but insertion had a worst case of _O(N)_ – scaling poorly for overloaded queues! Conversely, insertion to and removal from the min-heap scale logarithmically, delivering competitive average performance but really excelling in tail latencies. | Legacy (locked) MessageQueue| DeliQueue ---|---|--- Insert| _O(N)_| _O_(1) for calling thread _O(logN)_ for Looper thread Remove from head| _O_(1)| _O(logN)_ In the legacy queue implementation, producers and the consumer used a lock to coordinate exclusive access to the underlying singly-linked list. In DeliQueue, the Treiber stack handles concurrent access, and the single consumer handles ordering its work queue. Removal: consistency via tombstones DeliQueue is a hybrid data structure, joining a lock-free Treiber stack with a single-threaded min-heap. Keeping these two structures in sync without a global lock presents a unique challenge: a message might be physically present in the stack but logically removed from the queue. To solve this, DeliQueue uses a technique called “tombstoning.” Each Message tracks its position in the stack via the backwards and forwards pointers, its index in the heap’s array, and a boolean flag indicating whether it has been removed. When a Message is ready to run, the Looper thread will CAS its removed flag, then remove it from the heap and stack. When another thread needs to remove a Message, it doesn't immediately extract it from the data structure. Instead, it performs the following steps: 1. Logical removal: the thread uses a CAS to atomically set the Message’s removal flag from false to true. The Message remains in the data structure as evidence of its pending removal, a so-called “tombstone”. Once a Message is flagged for removal, DeliQueue treats it as if it no longer exists in the queue whenever it’s found. 2. Deferred cleanup: The actual removal from the data structure is the responsibility of the Looper thread, and is deferred until later. Rather than modifying the stack or heap, the remover thread adds the Message to another lock-free freelist stack. 3. Structural removal: Only the Looper can interact with the heap or remove elements from the stack. When it wakes up, it clears the freelist and processes the Messages it contained. Each Message is then unlinked from the stack and removed from the heap. This approach keeps all management of the heap single-threaded. It minimizes the number of concurrent operations and memory barriers required, making the critical path faster and simpler. ### Traversal: benign Java memory model data races Most concurrency APIs, such as Future in the Java standard library, or Kotlin’s Job and Deferred, include a mechanism to cancel work before it completes. An instance of one of these classes matches 1:1 with a unit of underlying work, and calling cancel on an object cancels the specific operations associated with them. Today’s Android devices have multi-core CPUs and concurrent, generational garbage collection. But when Android was first developed, it was too expensive to allocate one object for each unit of work. Consequently, Android’s Handler supports cancellation via numerous overloads of removeMessages - rather than removing a specific Message, it removes all Messages that match the specified criteria. In practice, this requires iterating through all Messages inserted before removeMessages was called and removing the ones that match. When iterating forward, a thread only requires one ordered atomic operation, to read the current head of the stack. After that, ordinary field reads are used to find the next Message. If the Looper thread modifies the next fields while removing Messages, the Looper’s write and another thread’s read are unsynchronized - this is a data race. Normally, a data race is a serious bug that can cause huge problems in your app - leaks, infinite loops, crashes, freezes, and more. However, under certain narrow conditions, data races can be benign within the Java Memory Model. Suppose we start with a stack of: We perform an atomic read of the head, and see A. A’s next pointer points to B. At the same time as we process B, the looper might remove B and C, by updating A to point to C and then D. Even though B and C are logically removed, B retains its next pointer to C, and C to D. The reading thread continues traversing through the detached removed nodes and eventually rejoins the live stack at D. By designing DeliQueue to handle races between traversal and removal, we allow for safe, lock-free iteration. Quitting: Native refcount Looper is backed by a native allocation that must be manually freed once the Looper has quit. If some other thread is adding Messages while the Looper is quitting, it could use the native allocation after it’s freed, a memory safety violation. We prevent this using a tagged refcount, where one bit of the atomic is used to indicate whether the Looper is quitting. Before using the native allocation, a thread reads the refcount atomic. If the quitting bit is set, it returns that the Looper is quitting and the native allocation must not be used. If not, it attempts a CAS to increment the number of active threads using the native allocation. After doing what it needs to, it decrements the count. If the quitting bit was set after its increment but before the decrement, and the count is now zero, then it wakes up the Looper thread. When the Looper thread is ready to quit, it uses CAS to set the quitting bit in the atomic. If the refcount was 0, it can proceed to free its native allocation. Otherwise, it parks itself, knowing that it will be woken up when the last user of the native allocation decrements the refcount. This approach does mean that the Looper thread waits for the progress of other threads, but only when it’s quitting. That only happens once and is not performance sensitive, and it keeps the other code for using the native allocation fully lock-free. There’s a lot of other tricks and complexity in the implementation. You can learn more about DeliQueue by reviewing the source code. Optimization: branchless programming While developing and testing DeliQueue, the team ran many benchmarks and carefully profiled the new code. One issue identified using the simpleperf tool was pipeline flushes caused by the Message comparator code. A standard comparator uses conditional jumps, with the condition for deciding which Message comes first simplified below: static int compareMessages(@NonNull Message m1, @NonNull Message m2) { if (m1 == m2) { return 0; } // Primary queue order is by when. // Messages with an earlier when should come first in the queue. final long whenDiff = m1.when - m2.when; if (whenDiff > 0) return 1; if (whenDiff < 0) return -1; // Secondary queue order is by insert sequence. // If two messages were inserted with the same `when`, the one inserted // first should come first in the queue. final long insertSeqDiff = m1.insertSeq - m2.insertSeq; if (insertSeqDiff > 0) return 1; if (insertSeqDiff < 0) return -1; return 0; } This code compiles to conditional jumps (b.le and cbnz instructions). When the CPU encounters a conditional branch, it can’t know whether the branch is taken until the condition is computed, so it doesn’t know which instruction to read next, and has to guess, using a technique called branch prediction. In a case like binary search, the branch direction will be unpredictably different at each step, so it’s likely that half the predictions will be wrong. Branch prediction is often ineffective in searching and sorting algorithms (such as the one used in a min-heap), because the cost of guessing wrong is larger than the improvement from guessing correctly. When the branch predictor guesses wrong, it must throw away the work it did after assuming the predicted value, and start again from the path that was actually taken - this is called a pipeline flush. To find this issue, we profiled our benchmarks using the branch-misses performance counter, which records stack traces where the branch predictor guesses wrong. We then visualized the results with Google pprof, as shown below: Recall that the original MessageQueue code used a singly-linked list for the ordered queue. Insertion would traverse the list in sorted order as a linear search, stopping at the first element that’s past the point of insertion and linking the new Message ahead of it. Removal from the head simply required unlinking the head. Whereas DeliQueue uses a min-heap, where mutations require reordering some elements (sifting up or down) with logarithmic complexity in a balanced data structure, where any comparison has an even chance of directing the traversal to a left child or to a right child. The new algorithm is asymptotically faster, but exposes a new bottleneck as the search code stalls on branch misses half the time. Realizing that branch misses were slowing down our heap code, we optimized the code using branch-free programming: // Branchless Logic static int compareMessages(@NonNull Message m1, @NonNull Message m2) { final long when1 = m1.when; final long when2 = m2.when; final long insertSeq1 = m1.insertSeq; final long insertSeq2 = m2.insertSeq; // signum returns the sign (-1, 0, 1) of the argument, // and is implemented as pure arithmetic: // ((num >> 63) | (-num >>> 63)) final int whenSign = Long.signum(when1 - when2); final int insertSeqSign = Long.signum(insertSeq1 - insertSeq2); // whenSign takes precedence over insertSeqSign, // so the formula below is such that insertSeqSign only matters // as a tie-breaker if whenSign is 0. return whenSign * 2 + insertSeqSign; } To understand the optimization, disassemble the two examples in Compiler Explorer and use LLVM-MCA, a CPU simulator that can generate an estimated timeline of CPU cycles. The original code: Index 01234567890123 [0,0] DeER . . . sub x0, x2, x3 [0,1] D=eER. . . cmp x0, #0 [0,2] D==eER . . cset w0, ne [0,3] .D==eER . . cneg w0, w0, lt [0,4] .D===eER . . cmp w0, #0 [0,5] .D====eER . . b.le #12 [0,6] . DeE---R . . mov w1, #1 [0,7] . DeE---R . . b #48 [0,8] . D==eE-R . . tbz w0, #31, #12 [0,9] . DeE--R . . mov w1, #-1 [0,10] . DeE--R . . b #36 [0,11] . D=eE-R . . sub x0, x4, x5 [0,12] . D=eER . . cmp x0, #0 [0,13] . D==eER. . cset w0, ne [0,14] . D===eER . cneg w0, w0, lt [0,15] . D===eER . cmp w0, #0 [0,16] . D====eER. csetm w1, lt [0,17] . D===eE-R. cmp w0, #0 [0,18] . .D===eER. csinc w1, w1, wzr, le [0,19] . .D====eER mov x0, x1 [0,20] . .DeE----R ret Note the one conditional branch, b.le,  which avoids comparing the insertSeq fields if the result is already known from comparing the when fields. The branchless code: Index 012345678 [0,0] DeER . . sub x0, x2, x3 [0,1] DeER . . sub x1, x4, x5 [0,2] D=eER. . cmp x0, #0 [0,3] .D=eER . cset w0, ne [0,4] .D==eER . cneg w0, w0, lt [0,5] .DeE--R . cmp x1, #0 [0,6] . DeE-R . cset w1, ne [0,7] . D=eER . cneg w1, w1, lt [0,8] . D==eeER add w0, w1, w0, lsl #1 [0,9] . DeE--R ret Here, the branchless implementation takes fewer cycles and instructions than even the shortest path through the branchy code - it’s better in all cases. The faster implementation plus the elimination of mispredicted branches resulted in a 5x improvement in some of our benchmarks! However, this technique is not always applicable. Branchless approaches generally require doing work that will be thrown away, and if the branch is predictable most of the time, that wasted work can slow your code down. In addition, removing a branch often introduces a data dependency. Modern CPUs execute multiple operations per cycle, but they can’t execute an instruction until its inputs from a previous instruction are ready. In contrast, a CPU can speculate about data in branches, and work ahead if a branch is predicted correctly. ## Testing and Validation Validating the correctness of lock-free algorithms is notoriously difficult! In addition to standard unit tests for continuous validation during development, we also wrote rigorous stress tests to verify queue invariants and to attempt to induce data races if they existed. In our test labs we could run millions of test instances on emulated devices and on real hardware. With Java ThreadSanitizer (JTSan) instrumentation, we could use the same tests to also detect some data races in our code. JTSan did not find any problematic data races in DeliQueue, but - surprisingly -actually detected two concurrency bugs in the Robolectric framework, which we promptly fixed. To improve our debugging capabilities, we built new analysis tools. Below is an example showing an issue in Android platform code where one thread is overloading another thread with Messages, causing a large backlog, visible in Perfetto thanks to the MessageQueue instrumentation feature that we added. To enable MessageQueue tracing in the system_server process, include the following in your Perfetto configuration: data_sources { config { name: "track_event" target_buffer: 0 # Change this per your buffers configuration track_event_config { enabled_categories: "mq" } } } Impact DeliQueue improves system and app performance by eliminating locks from MessageQueue. * Synthetic benchmarks: multi-threaded insertions into busy queues is up to 5,000x faster than the legacy MessageQueue, thanks to improved concurrency (the Treiber stack) and faster insertions (the min-heap). * In Perfetto traces acquired from internal beta testers, we see a reduction of 15% in app main thread time spent in lock contention. * On the same test devices, the reduced lock contention leads to significant improvements to the user experience, such as: * -4% missed frames in apps. * -7.7% missed frames in System UI and Launcher interactions. * -9.1% in time from app startup to the first frame drawn, at the 95%ile. ## Next steps DeliQueue is rolling out to apps in Android 17. App developers should review preparing your app for the new lock-free MessageQueue on the Android Developers blog to learn how to test their apps. ## References [1] Treiber, R.K., 1986. Systems programming: Coping with parallelism. International Business Machines Incorporated, Thomas J. Watson Research Center. [2] Goetz, B., Peierls, T., Bloch, J., Bowbeer, J., Holmes, D., & Lea, D. (2006). Java Concurrency in Practice. Addison-Wesley Professional.
17.02.2026 16:00 👍 0 🔁 0 💬 0 📌 0
Preview
Prepare your app for the resizability and orientation changes in Android 17 _Posted by Miguel Montemayor, Developer Relations Engineer, Android  _ With the release of Android 16 in 2025, we shared our vision for a device ecosystem where apps adapt seamlessly to any screen—whether it’s a phone, foldable, tablet, desktop, car display, or XR. Users expect their apps to work everywhere. Whether multitasking on a tablet, unfolding a device to read comfortably, or running apps in a desktop windowing environment, users expect the UI to fill the available display space and adapt to the device posture. We introduced significant changes to orientation and resizability APIs to facilitate adaptive behavior, while providing a temporary opt-out to help you make the transition. We’ve already seen many developers successfully adapt to this transition when targeting API level 36. Now with the release of the Android 17 Beta, we’re moving to the next phase of our adaptive roadmap: Android 17 (API level 37) removes the developer opt-out for orientation and resizability restrictions on large screen devices (sw > 600 dp). When you target API level 37, your app must be capable of adapting to a variety of display sizes. The behavior changes ensure that the Android ecosystem offers a consistent, high-quality experience on all device form factors. What’s changing in Android 17 Apps targeting Android 17 must ensure their compatibility with the phase out of manifest attributes and runtime APIs introduced in Android 16. We understand for some apps this may be a big transition, so we’ve included best practices and tools for helping avoid common issues later in this blog post. No new changes have been introduced since Android 16, but the developer opt-out is no longer possible. As a reminder: when your app is running on a large screen—where large screen means that the smaller dimension of the display is greater than or equal to 600 dp—the following manifest attributes and APIs are ignored: Note: As previously mentioned with Android 16, these changes do not apply for screens that are smaller than sw 600 dp or apps categorized as games based on the android:appCategory flag. **Manifest attributes/API**| **Ignored values** ---|--- screenOrientation| portrait, reversePortrait, sensorPortrait, userPortrait, landscape, reverseLandscape, sensorLandscape, userLandscape setRequestedOrientation()| portrait, reversePortrait, sensorPortrait, userPortrait, landscape, reverseLandscape, sensorLandscape, userLandscape resizeableActivity| all minAspectRatio| all maxAspectRatio| all Also, users retain control. In the aspect ratio settings, users can explicitly opt-in to using the app’s requested behavior. ### Prepare your app Apps will need to support landscape and portrait layouts for display sizes in the full range of aspect ratios in which users can choose to use apps, including resizable windows, as there will no longer be a way to restrict the aspect ratio and orientation to portrait or to landscape. Test your app Your first step is to test your app with these changes to make sure the app works well across display sizes. Use Android 17 Beta 1 with the Pixel Tablet and Pixel Fold series emulators in Android Studio, and set the targetSdkPreview = “CinnamonBun”. Alternatively, you can use the app compatibility framework by enabling the UNIVERSAL_RESIZABLE_BY_DEFAULT flag if your app does not target API level 36 yet. We have additional tools to ensure your layouts adapt correctly. You can automatically audit your UI and get suggestions to make your UI more adaptive with Compose UI Check, and simulate specific display characteristics in your tests using DeviceConfigurationOverride. For apps that have historically restricted orientation and aspect ratio, we commonly see issues with skewed or misoriented camera previews, stretched layouts, inaccessible buttons, or loss of user state when handling configuration changes. Let’s take a look at some strategies for addressing these common issues. Ensure camera compatibility A common problem on landscape foldables or for aspect ratio calculations in scenarios like multi-window, desktop windowing, or connected displays, is when the camera preview appears stretched, rotated, or cropped. _Ensure your camera preview isn’t stretched or rotated._ This issue often happens on large screen and foldable devices because apps assume fixed relationships between camera features (like aspect ratio and sensor orientation) and device features (like device orientation and natural orientation). To ensure your camera preview adapts correctly to any window size or orientation, consider these four solutions: Solution 1: Jetpack CameraX (preferred) The simplest and most robust solution is to use the Jetpack CameraX library. Its PreviewView UI element is designed to handle all preview complexities automatically: * PreviewView correctly adjusts for sensor orientation, device rotation, and scaling * PreviewView maintains the aspect ratio of the camera image, typically by centering and cropping (FILL_CENTER) * You can set the scale type to FIT_CENTER to letterbox the preview if needed For more information, see Implement a preview in the CameraX documentation. Solution 2: CameraViewfinder If you are using an existing Camera2 codebase, the CameraViewfinder library (backward compatible to API level 21) is another modern solution. It simplifies displaying the camera feed by using a TextureView or SurfaceView and applying all the necessary transformations (aspect ratio, scale, and rotation) for you. For more information, see the Introducing Camera Viewfinder blog post and Camera preview developer guide. Solution 3: Manual Camera2 implementation If you can't use CameraX or CameraViewfinder, you must manually calculate the orientation and aspect ratio and ensure the calculations are updated on each configuration change: * Get the camera sensor orientation (for example, 0, 90, 180, 270 degrees) from CameraCharacteristics * Get the device's current display rotation (for example, 0, 90, 180, 270 degrees) * Use the camera sensor orientation and display rotation values to determine the necessary transformations for your SurfaceView or TextureView * Ensure the aspect ratio of your output Surface matches the aspect ratio of the camera preview to prevent distortion Important: Note the camera app might be running in a portion of the screen, either in multi-window or desktop windowing mode or on a connected display. For this reason, screen size should not be used to determine the dimensions of the camera viewfinder; use window metrics instead. Otherwise you risk a stretched camera preview. For more information, see the Camera preview developer guide and Your Camera app on different form factors video. Solution 4: Perform basic camera actions using an Intent If you don't need many camera features, a simple and straightforward solution is to perform basic camera actions like capturing a photo or video using the device's default camera application. In this case, you can simply use an Intent instead of integrating with a camera library, for easier maintenance and adaptability. For more information, see Camera intents. Avoid stretched UI or inaccessible buttons If your app assumes a specific device orientation or display aspect ratio, the app may run into issues when it’s now used across various orientations or window sizes. Ensure buttons, textfields, and other elements aren’t stretched on large screens. You may have set buttons, text fields, and cards to fillMaxWidth or match_parent. On a phone, this looks great. However, on a tablet or foldable in landscape, UI elements stretch across the entire large screen. In Jetpack Compose, you can use the widthIn modifier to set a maximum width for components to avoid stretched content: Box( contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize() ) { Column( modifier = Modifier .widthIn(max = 300.dp) // Prevents stretching beyond 300dp .fillMaxWidth() // Fills width up to 300dp .padding(16.dp) ) { // Your content } } If a user opens your app in landscape orientation on a foldable or tablet, action buttons like Save or Login at the bottom of the screen may be rendered offscreen. If the container is not scrollable, the user can be blocked from proceeding. In Jetpack Compose, you can add a verticalScroll modifier to your component: Column( modifier = Modifier .fillMaxSize() .verticalScroll(rememberScrollState()) .padding(16.dp) ) By combining max-width constraints with vertical scrolling, you ensure your app remains functional and usable, regardless of how wide or short the app window size becomes. ** ** See our guide on building adaptive layouts. ** ** Preserve state with configuration changes Removing orientation and aspect ratio restrictions means your app's window size will change much more frequently. Users may rotate their device, fold/unfold it, or resize your app dynamically in split-screen or desktop windowing modes. By default, these configuration changes destroy and recreate your activity. If your app does not properly manage this lifecycle event, users will have a frustrating experience: scroll positions are reset to the top, half-filled forms are wiped clean, and navigation history is lost. To ensure a seamless adaptive experience, it’s critical your app preserves state through these configuration changes. With Jetpack Compose, you can opt-out of recreation, and instead allow window size changes to recompose your UI to reflect the new amount of space available. See our guide on saving UI state. ### Targeting API level 37 by August 2027 If your app previously opted out of these changes when targeting API level 36, your app will only be impacted by the Android 17 opt-out removal after your app targets API level 37. To help you plan ahead and make the necessary adjustments to your app, here’s the timeline when these changes will take effect: ** ** * Android 17: Changes described above will be the baseline experience for large screen devices (smallest screen width > 600 dp) for apps that target API level 37. Developers will not have an option to opt-out. ** ** The deadlines for targeting a specific API level are app-store specific. For Google Play, new apps and updates will be required to target API level 37, making this behavior mandatory for distribution in August 2027. ### Preparing for Android 17 Refer to the Android 17 changes page for all changes impacting apps in Android 17. To test your app, download Android 17 Beta 1 and update to targetSdkPreview = “CinnamonBun” or use the app compatibility framework to enable specific changes. The future of Android is adaptive, and we’re here to help you get there. As you prepare for Android 17, we encourage you to review our guides for building adaptive layouts and our large screen quality guidelines. These resources are designed to help you handle multiple form factors and window sizes with confidence. Don’t wait. Start getting ready for Android 17 today!
13.02.2026 19:34 👍 0 🔁 0 💬 0 📌 0
Preview
The First Beta of Android 17 _Posted by Matthew McCullough, VP of Product Management, Android Developer_ Today we're releasing the first beta of Android 17, continuing our work to build a platform that prioritizes privacy, security, and refined performance. This build continues our work for more adaptable Android apps, introduces significant enhancements to camera and media capabilities, new tools for optimizing connectivity, and expanded profiles for companion devices. This release also highlights a fundamental shift in the way we're bringing new releases to the developer community, from the traditional Developer Preview model to the Android Canary program ## Beyond the Developer Preview Android has replaced the traditional "Developer Preview" with a continuous Canary channel. This new "always-on" model offers three main benefits: * Faster Access: Features and APIs land in Canary as soon as they pass internal testing, rather than waiting for a quarterly release. * Better Stability: Early "battle-testing" in Canary results in a more polished Beta experience with new APIs and behavior changes that are closer to being final. * Easier Testing: Canary supports OTA updates (no more manual flashing) and, as a separate update channel, more easily integrates with CI workflows and gives you the earliest window to give immediate feedback on upcoming potential changes. The Android 17 schedule We're going to be moving quickly from this Beta to our Platform Stability milestone, targeted for March. At this milestone, we'll deliver final SDK/NDK APIs and largely final app-facing behaviors. From that time you’ll have several months before the final release to complete your testing. ### **A year of releases** We plan for Android 17 to continue to get updates in a series of quarterly releases. The upcoming release in Q2 is the only one where we introduce planned app breaking behavior changes. We plan to have a minor SDK release in Q4 with additional APIs and features. ## **Orientation and resizability restrictions** With the release of the Android 17 Beta, we’re moving to the next phase of our adaptive roadmap: Android 17 (API level 37) removes the developer opt-out for orientation and resizability restrictions on large screen devices (sw > 600 dp). When your app targets SDK 37, it must be ready to adapt. Users expect their apps to work everywhere—whether multitasking on a tablet, unfolding a device, or using a desktop windowing environment—and they expect the UI to fill the space and respect their device posture. ### Key Changes for SDK 37 Apps targeting Android 17 must ensure compatibility with the phase-out of manifest attributes and runtime APIs introduced in Android 16. When running on a large screen (smaller dimension ≥ 600dp), the following attributes and APIs will be ignored: **Manifest attributes/API**| **Ignored values** ---|--- screenOrientation| portrait, reversePortrait, sensorPortrait, userPortrait, landscape, reverseLandscape, sensorLandscape, userLandscape setRequestedOrientation()| portrait, reversePortrait, sensorPortrait, userPortrait, landscape, reverseLandscape, sensorLandscape, userLandscape resizeableActivity| all minAspectRatio| all maxAspectRatio| all ### Exemptions and User Control These changes are specific to large screens; they do not apply to screens smaller than sw600dp (including traditional slate form factor phones). Additionally, apps categorized as games (based on the android:appCategory flag) are exempt from these restrictions. It is also important to note that users remain in control. They can explicitly opt-in/out to using an app’s default behavior via the system's aspect ratio settings. **Updates to configuration changes** To improve app compatibility and help minimize interrupted video playback, dropped input, and other types of disruptive state loss, we are updating the default behavior for Activity recreation. Starting with Android 17, the system will no longer restart activities by default for specific configuration changes that typically do not require a UI recreation, including CONFIG_KEYBOARD, CONFIG_KEYBOARD_HIDDEN, CONFIG_NAVIGATION, CONFIG_UI_MODE (when only UI_MODE_TYPE_DESK is changed), CONFIG_TOUCHSCREEN, and CONFIG_COLOR_MODE. Instead, running activities will simply receive these updates via onConfigurationChanged. If your application relies on a full restart to reload resources for these changes, you must now explicitly opt-in using the new android:recreateOnConfigChanges manifest attribute, which allows you to specify which configuration changes should trigger a complete activity lifecycle (from stop, to destroy and creation again), together with the related constants mcc, mnc, and the new ones keyboard, keyboardHidden, navigation, touchscreen and colorMode. **Prepare Your App** We’ve released tools and documentation to make it easy for you. Our focused blog post has more guidance, with strategies to address common issues. Apps will need to support landscape and portrait layouts for window sizes across the full range of aspect ratios, as restricting orientation or aspect ratio will no longer be an option. We recommend testing your app using the Android 17 Beta 1 with Pixel Tablet or Pixel Fold emulators (configured to targetSdkPreview = "CinnamonBun") or by using the app compatibility framework to enable UNIVERSAL_RESIZABLE_BY_DEFAULT on Android 16 devices. ### Performance ### Lock-free MessageQueue In Android 17, apps targeting SDK 37 or higher will receive a new implementation of android.os.MessageQueue where the implementation is lock-free. The new implementation improves performance and reduces missed frames, but may break clients that reflect on MessageQueue private fields and methods. ### Generational garbage collection Android 17 introduces generational garbage collection to ART's Concurrent Mark-Compact collector. This optimization introduces more frequent, less resource-intensive young-generation collections alongside full-heap collections. aiming to reduce overall garbage collection CPU cost and time duration. ART improvements are also available to over a billion devices running Android 12 (API level 31) and higher through Google Play System updates. ### Static final fields now truly final Starting from Android 17 apps targeting Android 17 or later won’t be able to modify “static final” fields, allowing the runtime to apply performance optimizations more aggressively. An attempt to do so via reflection (and deep reflection) will always lead to IllegalAccessException being thrown. Modifying them via JNI’s SetStatic<Type>Field methods family will immediately crash the application. ### Custom Notification View Restrictions To reduce memory usage we are restricting the size of custom notification views. This update closes a loophole that allows apps to bypass existing limits using URIs. This behavior is gated by the target SDK version and takes effect for apps targeting API 37 and higher. ### New performance debugging ProfilingManager triggers We’ve introduced several new system triggers to ProfilingManager to help you collect in-depth data to debug performance issues. These triggers are TRIGGER_TYPE_COLD_START, TRIGGER_TYPE_OOM, and TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE. To understand how to set up the new system triggers, check out the trigger-based profiling and retrieve and analyze profiling data documentation. Media and Camera Android 17 brings professional-grade tools to media and camera apps, with features like seamless transitions and standardized loudness. **Dynamic Camera Session Updates** We have introduced updateOutputConfigurations() to CameraCaptureSession. This allows you to dynamically attach and detach output surfaces without the need to reconfigure the entire camera capture session. This change enables seamless transitions between camera use cases and modes (such as shooting still images vs shooting videos) without the memory cost and code complexity of configuring and holding onto all camera output surfaces that your app might need during camera start up. This helps to eliminate user-visible glitches or freezes during operation. fun updateCameraSession(session: CameraCaptureSession, newOutputConfigs: List<OutputConfiguration>)) { // Dynamically update the session without closing and reopening try { // Update the output configurations session.updateOutputConfigurations(newOutputConfigs) } catch (e: CameraAccessException) { // Handle error } } Logical multi-camera device metadata When working with logical cameras that combine multiple physical camera sensors, you can now request additional metadata from all active physical cameras involved in a capture, not just the primary one. Previously, you had to implement workarounds, sometimes allocating unnecessary physical streams, to obtain metadata from secondary active cameras (e.g., during a lens switch for zoom where a follower camera is active). This feature introduces a new key, LOGICAL_MULTI_CAMERA_ADDITIONAL_RESULTS, in CaptureRequest and CaptureResult. By setting this key to ON in your CaptureRequest, the TotalCaptureResult will include metadata from these additional active physical cameras. You can access this comprehensive metadata using TotalCaptureResult.getPhysicalCameraTotalResults() to get more detailed information that may enable you to optimize resource usage in your camera applications. ### Versatile Video Coding (VVC) Support Android 17 adds support for the Versatile Video Coding (VVC) standard. This includes defining the video/vvc MIME type in MediaFormat, adding new VVC profiles in MediaCodecInfo, and integrating support into MediaExtractor. This feature will be coming to devices with hardware decode support and capable drivers. ### Constant Quality for Video Recording We have added setVideoEncodingQuality() to MediaRecorder. This allows you to configure a constant quality (CQ) mode for video encoders, giving you finer control over video quality beyond simple bitrate settings. ### Background Audio Hardening Starting in Android 17, the audio framework will enforce restrictions on background audio interactions including audio playback, audio focus requests, and volume change APIs to ensure that these changes are started intentionally by the user. If the app tries to call audio APIs while the application is not in a valid lifecycle, the audio playback and volume change APIs will fail silently without an exception thrown or failure message provided. The audio focus API will fail with the result code AUDIOFOCUS_REQUEST_FAILED. ## Privacy and Security ### Deprecation of Cleartext Traffic Attribute The android:usesCleartextTraffic attribute is now deprecated. If your app targets (Android 17) or higher and relies on usesCleartextTraffic="true" without a corresponding Network Security Configuration, it will default to disallowing cleartext traffic. You are encouraged to migrate to Network Security Configuration files for granular control. **HPKE Hybrid Cryptography** We are introducing a public Service Provider Interface (SPI) for an implementation of HPKE hybrid cryptography, enabling secure communication using a combination of public key and symmetric encryption (AEAD). Connectivity and Telecom ### Enhanced VoIP Call History We are introducing user preference management for app VoIP call history integration. This includes support for caller and participant avatar URIs in the system dialer, enabling granular user control over call log privacy and enriching the visual display of integrated VoIP call logs. ### Wi-Fi Ranging and Proximity Wi-Fi Ranging has been enhanced with new Proximity Detection capabilities, supporting continuous ranging and secure peer-to-peer discovery. Updates to Wi-Fi Aware ranging include new APIs for peer handles and PMKID caching for 11az secure ranging. ## Developer Productivity and Tools ### Updates for companion device apps We have introduced two new profiles to the CompanionDeviceManager to improve device distinction and permission handling: * Medical Devices: This profile allows medical device mobile applications to request all necessary permissions with a single tap, simplifying the setup process. * Fitness Trackers: The DEVICE_PROFILE_FITNESS_TRACKER profile allows companion apps to explicitly indicate they are managing a fitness tracker. This ensures accurate user experiences with distinct icons while reusing existing watch role permissions. Also, the CompanionDeviceManager now offers a unified dialog for device association and Nearby permission requests. You can leverage the new setExtraPermissions method in AssociationRequest.Builder to bundle nearby permission prompts within the existing association flow, reducing the number of dialogs presented to the user. **Get started with Android 17** You can enroll any supported Pixel device to get this and future Android Beta updates over-the-air. If you don’t have a Pixel device, you can use the 64-bit system images with the Android Emulator in Android Studio. If you are currently in the Android Beta program, you will be offered an over-the-air update to Beta 1. If you have Android 26Q1 Beta and would like to take the final stable release of 26Q1 and exit Beta, you need to ignore the over-the-air update to 26Q2 Beta 1 and wait for the release of 26Q1. We're looking for your feedback so please report issues and submit feature requests on the feedback page. The earlier we get your feedback, the more we can include in our work on the final release. For the best development experience with Android 17, we recommend that you use the latest preview of Android Studio (Panda). Once you’re set up, here are some of the things you should do: * Compile against the new SDK, test in CI environments, and report any issues in our tracker on the feedback page. * Test your current app for compatibility, learn whether your app is affected by changes in Android 17, and install your app onto a device or emulator running Android 17 and extensively test it. We’ll update the preview/beta system images and SDK regularly throughout the Android 17 release cycle. Once you’ve installed a beta build, you’ll automatically get future updates over-the-air for all later previews and Betas. For complete information, visit the Android 17 developer site. Join the conversation As we move toward Platform Stability and the final stable release of Android 17 later this year, your feedback remains our most valuable asset. Whether you’re an early adopter on   the Canary channel or an app developer testing on Beta 1, consider joining our communities and filing feedback. We’re listening.
13.02.2026 19:23 👍 0 🔁 0 💬 0 📌 0
Preview
Accelerating your insights with faster, smarter monetization data and recommendations <name content="IMG" twitter:image=""><p><em>Posted by&nbsp;</em><span style="font-style: italic; white-space-collapse: preserve;"><span style="font-family: inherit;">Phalene Gowling, Product Manager, Google Play</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="font-family: inherit;"></span></p><div class="separator" style="clear: both; text-align: center;"><span style="font-family: inherit;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUu8IbGbe8xG6oEOPleIJJBclT5w4KzFwx0J6PDnDwjNtswk6F5V2AfGHLEIeiRAsh4aoYPRgg1TY1jd_oSNmEqN8yIUvEkKQdxc9ZlOH9dNhEGMgChsqSsNbCx2YJVxOonczumFbBr-ILpzb3fuDbe2BhCNwE5S6yR-bGd7RtOIF-EdYcJhAUptCfGrY/s4209/260127_Header.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1253" data-original-width="4209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUu8IbGbe8xG6oEOPleIJJBclT5w4KzFwx0J6PDnDwjNtswk6F5V2AfGHLEIeiRAsh4aoYPRgg1TY1jd_oSNmEqN8yIUvEkKQdxc9ZlOH9dNhEGMgChsqSsNbCx2YJVxOonczumFbBr-ILpzb3fuDbe2BhCNwE5S6yR-bGd7RtOIF-EdYcJhAUptCfGrY/s16000/260127_Header.png" /></a></span></div><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To build a thriving business on Google Play, you need more than just data&nbsp; </span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">– </span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">you need a clear path to action. Today, we’re announcing a suite of upgrades to the Google Play Console and beyond, giving you greater visibility into your financial performance and specific, data-backed steps to improve it.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span><span style="background-color: transparent; color: black; font-family: inherit; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></span></p><p><span><span id="docs-internal-guid-345b2028-7fff-c651-aa6a-f452e1dea9a9" style="font-family: inherit;"></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">From new, actionable recommendations to more granular sales reporting, here’s how we’re helping you maximize your ROI.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span id="docs-internal-guid-ecdbda26-7fff-b144-a674-48fd0db048d4"><span style="font-family: inherit; font-size: x-large;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">New: Monetization insights and recommendations</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span></span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span><span style="font-family: inherit; font-style: italic; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Launch Status: Rolling out today</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">The</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;"> Monetize with Play</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> overview page is designed to be your ultimate command center. Today, we are upgrading it with a new dynamic insights section designed to </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">give you a clearer view of your revenue drivers.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"></p><div class="separator" style="clear: both;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG2PJK3eO0myJfVBYX5UaeTzmjBXj9FX_oqYFx3UjdX3tjpPzh-D7ChSh5mFXxoyj9cj379KL1CzOh_JRnWfPbanAf5aR_XgAFHOw49coGHuApSQGmJSIn3E-wSrhh_H8fshWd-RqzHt4qHwWY3p8eeXqpTkTCJmh4sGPx386iJCunarcEV0eMqdif7Ho/s16000/VOP+Recos%20(1).gif" /></div><div class="separator" style="clear: both;"><span style="font-family: inherit; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">This new insights carousel highlights the visible and invisible value Google Play delivers to your bottom line – including recovered revenue. Alongside these insights, y</span><span style="white-space-collapse: preserve;">ou can now track these critical signals alongside your core performance metrics:</span></span></div><div class="separator" style="clear: both;"><span style="font-family: inherit; white-space-collapse: preserve;"><br /></span></div></name><span id="docs-internal-guid-e4116b9d-7fff-4204-6c17-087bd39debf2"><span style="font-family: inherit;"><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px; text-align: left;"><li><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Optimize conversion:</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> Track your new </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Cart Conversion Rate</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">.</span></li><li aria-level="1" style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; text-wrap-mode: wrap; vertical-align: baseline;">Reduce churn:</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-wrap-mode: wrap; vertical-align: baseline;"> Track cancelled subscriptions over time.</span></p></li><li aria-level="1" style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; text-wrap-mode: wrap; vertical-align: baseline;">Optimize pricing:</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-wrap-mode: wrap; vertical-align: baseline;"> Monitor your Average Revenue Per Paying User (ARPPU).</span></p></li><li aria-level="1" style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p role="presentation" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; text-wrap-mode: wrap; vertical-align: baseline;">Increase buyer reach:</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-wrap-mode: wrap; vertical-align: baseline;"> Analyze how much of your engaged audience convert to buyers.</span></p></li></ul></span></span><span><span style="font-family: inherit;"><div><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">But we aren’t just showing you the data – we’re helping you act on it</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">. Starting today, Play Console will surface customized, </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">actionable recommendations</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">. If there are relevant opportunities – for example, a high churn rate – we will suggest specific, high-impact steps to help you reach your next monetization goal. Recommendations include effort levels and estimated ROI (where available), helping you prioritize your roadmap based on actual business value. </span><a href="https://support.google.com/googleplay/android-developer/answer/16770947" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">Learn more</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">.</span></span></div><div><span id="docs-internal-guid-0e3541ed-7fff-eeb6-8b17-7ab0bae48408"><div><br /></div></span></div></span></span><div><span><span style="font-family: inherit;"><br /></span></span><div class="separator" style="clear: both;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_FupxqyHb3fm18u-MwmVOQQJ03q1oP83VNdLjgPIDFJyJfZC3VA3CHw87e5lTiC3UbHA5nsn8SiANsF1vVk344AyGZGVbfkYY0itRhTfO3JeQDmmkind4ZEVluipANEEwqsiU9A_EiwZyIF0AuabfwV2pFp1uTdobdjK7STe0Q6CWb6cPIPo7_wtDq2Q/s16000/Recos.png" /></div><div class="separator" style="clear: both;"><span style="font-family: inherit; font-size: x-large; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: inherit; font-size: x-large; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Granular visibility: Sales Channel reporting</span><span style="font-family: inherit; font-size: x-large; font-style: italic; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span></div><div class="separator" style="clear: both;"><span style="font-style: italic; white-space-collapse: preserve;"><span style="font-family: inherit;">Launch Status: Recently launched</span></span></div></div><span><span style="font-family: inherit;"><span id="docs-internal-guid-0232a2b0-7fff-95d7-7139-7c41d4b515eb"><div><span style="font-style: italic; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span id="docs-internal-guid-444ea79a-7fff-321c-0a0a-ad9e1467ed9f"><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We recently rolled out new </span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Sales Channel data</span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in your financial reporting. This allows you to attribute revenue to specific surfaces - including your app, the Play Store, and platforms like Google Play Games on PC.&nbsp;</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span><span id="docs-internal-guid-497347cd-7fff-6bd8-203e-f29d90b1b420" style="font-family: inherit;"></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For native-PC game developers and media &amp; entertainment subscription businesses alike, this granularity allows you to calculate the precise ROI of your cross-platform investments and understand exactly which channels are driving your growth. </span><a href="https://support.google.com/googleplay/android-developer/answer/6135870#zippy=%2Cestimated-sales" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Learn more</span></a><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></span></p><div style="font-family: Arial, sans-serif; font-size: 11pt;"><span style="font-size: 11pt; font-style: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline;"><br /></span></div></span></span></div></span></span></span><div class="separator" style="clear: both;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqeq3IqcooM2gNTJi7fVGvw49OF8ocTaj0FZg6CZF-s0xwar5pq7zNC6GuYc6COEKzOqwmb7HmLkEzpao3ybFRkZFMxFI4BB_uIJfwen3MzmI24vaK9bN7w5FfA5-FTk1tkPo9_N__cEO3MeTe74ZeoQtGDMGGQ-Ny5yMBSTKUW9e7pASztV670aEIdH0/s16000/20_download.gif" /></div><div class="separator" style="clear: both;"><span style="font-family: inherit; font-size: x-large; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: inherit; font-size: x-large; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Operational efficiency: The Orders API</span><span style="font-family: inherit; font-size: x-large; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span></div><div class="separator" style="clear: both;"><span style="font-family: inherit; font-style: italic; white-space-collapse: preserve;">Launch Status: Available now</span></div><span><span style="font-family: inherit;"><span id="docs-internal-guid-598fa3a1-7fff-f90f-7c15-06df086d902c" style="font-family: inherit;"><div><span style="font-style: italic; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span id="docs-internal-guid-598fa3a1-7fff-f90f-7c15-06df086d902c"><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span id="docs-internal-guid-5e506628-7fff-55f4-43a4-ead966fb356f"><span><span style="font-style: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline;">The </span><a href="https://developers.google.com/android-publisher/api-ref/rest/v3/orders" style="text-decoration-line: none;"><span style="color: #1155cc; font-style: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline;">Orders API</span></a><span style="font-style: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline;"> provides programmatic access to one-time and recurring order transaction details. If you haven't integrated it yet, this API allows you to ingest real-time data directly into your internal dashboards for faster reconciliation and improved customer support.</span></span></span></p></span></span></div></span></span></span><div class="separator" style="clear: both;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRm6oskAWoQqp64r1eyOonGHsXbRjubwH9emshyphenhyphen6Rd4yMbMklBf5WBQcXWanyj6qiwcA3JBtu-vTU7uw7ouyt6WwrJBc8OSEJ5ZuFkLeWLOoioCAprr-i006Ykg8Ewn3Dp4WobAkIvBsJ6VGXnbkR8WZrenez7UfZnPzbqpauNM74baDpFHmg8bSUhT1Q/s16000/Frame%201739328245.png" /></div><div class="separator" style="clear: both;"><span style="font-family: inherit; white-space-collapse: preserve;">Feedback so far has been overwhelmingly positive: </span></div><span><span style="font-family: inherit;"><div><span style="font-family: inherit;"><blockquote><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Level Infinite (Tencent) </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">says the API </span><span style="font-style: italic; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">&nbsp;“works so well that we want every app to use it."</span></blockquote></span></div><div><span id="docs-internal-guid-dbd2c3c4-7fff-567b-08bd-1fbb6d50ea36"><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="font-family: inherit; font-size: x-large;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Continuous improvements towards objective-led reporting</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">&nbsp;</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">You’ve told us that the biggest challenge isn't just accessing data, but connecting the dots across different metrics to see the full picture. We’re enhancing reporting that goes beyond data dumps to provide straightforward, actionable insights that help you reach business objectives faster.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt;"><span id="docs-internal-guid-7cb3419b-7fff-8f74-3af6-346681e9f278"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Our goal is to create a more cohesive product experience centered around </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">your</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">objectives</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">. By shifting from static reporting to dynamic, goal-orientated tools, we’re making it easier to track and optimize for revenue, conversion rates, and churn. These updates are just the beginning of a transformation designed to help you turn data into measurable growth.</span></span></span></p><div><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span style="white-space-collapse: preserve;"><br /></span></div></span></span>
29.01.2026 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
How Automated Prompt Optimization Unlocks Quality Gains for ML Kit’s GenAI Prompt API <name content="IMG" twitter:image=""><p><em>Posted by Chetan Tekur, PM at AI Innovation and Research, Chao Zhao, SWE at AI Innovation and Research, Paul Zhou, Prompt Quality Lead at GCP Cloud AI and Industry Solutions, and Caren Chang, Developer Relations Engineer at Android</em></p><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzM3vaSLDllo5iph05S1l97RLQ1XKgYStArRkBvdEJ2qejXt-frMkDB_qHxsjoVEQDVXCPjOUYwtXDLB91MaeddmZsFqgeWKFyokTcWTMRY2rxuGp9Y-5ZCRDc7SfivBUukNaC3wmLfVMzykxvl3fm3kh_Be_C-Zo2BdeJhU87mddSniZTJGa0efyWd9Y/s4209/Prompt-API-Banner%20(1).png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1253" data-original-width="4209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzM3vaSLDllo5iph05S1l97RLQ1XKgYStArRkBvdEJ2qejXt-frMkDB_qHxsjoVEQDVXCPjOUYwtXDLB91MaeddmZsFqgeWKFyokTcWTMRY2rxuGp9Y-5ZCRDc7SfivBUukNaC3wmLfVMzykxvl3fm3kh_Be_C-Zo2BdeJhU87mddSniZTJGa0efyWd9Y/s16000/Prompt-API-Banner%20(1).png" /></a></div><span style="font-family: inherit;"><br /><span id="docs-internal-guid-e305b9fe-7fff-1e4b-b89c-fc9b239792e5"><span style="font-family: inherit;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">To further help bring your ML Kit Prompt API use cases to production, we are excited to announce </span><a href="https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/prompts/zero-shot-optimizer#optimizing_for_smaller_models" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">Automated Prompt Optimization (APO) targeting On-Device models on Vertex AI</span></a><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">. Automated Prompt Optimization is a tool that helps you automatically find the optimal prompt for your use cases.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">The era of On-Device AI is no longer a promise—it is a production reality. With the release of </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Gemini Nano v3</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, we are placing unprecedented language understanding and multimodal capabilities directly into the palms of users. Through the Gemini Nano family of models, we have wide coverage of supported devices across the Android Ecosystem. But for developers building the next generation of intelligent apps, access to a powerful model is only step one. The real challenge lies in </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">customization</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">: How do you tailor a foundation model to expert-level performance for your specific use case without breaking the constraints of mobile hardware?</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">In the server-side world, the larger LLMs tend to be highly capable and require less domain adaptation. Even when needed, more advanced options such as LoRA (Low-Rank Adaptation) fine-tuning can be feasible options. However, the unique architecture of Android AICore prioritizes a </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">shared, memory-efficient system model</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">. This means that deploying custom LoRA adapters for every individual app comes with challenges on these shared system services.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">But there is an alternate path that can be equally impactful. By leveraging </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Automated Prompt Optimization (APO)</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> on Vertex AI, developers can achieve quality approaching fine-tuning, all while working seamlessly within the native Android execution environment. By focusing on superior system instruction, APO enables developers to tailor model behavior with greater robustness and scalability than traditional fine-tuning solutions.</span></p><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Note: </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Gemini Nano V3 is a quality optimized version of the highly acclaimed </span><a href="https://developers.googleblog.com/en/introducing-gemma-3n/" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">Gemma 3N</span></a><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> model. Any prompt optimizations that are made on the open source Gemma 3N model will apply to Gemini Nano V3 as well. On </span><a href="https://developers.google.com/ml-kit/genai#prompt-device" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">supported devices</span></a><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, ML Kit GenAI APIs leverage the </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">nano-v3</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> model to maximize the quality for Android Developers. </span></span></span><br /></span><p></p></name><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span id="docs-internal-guid-ea993e2b-7fff-8452-d660-3bc80be09d93"><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit; font-size: x-large;">Automated Prompt Optimization (APO)</span></span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To further help bring your ML Kit Prompt API use cases to production, we are excited to announce </span><a href="https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/prompts/zero-shot-optimizer#optimizing_for_smaller_models" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Automated Prompt Optimization (APO) targeting On-Device models on Vertex AI</span></a><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Automated Prompt Optimization is a tool that helps you automatically find the optimal prompt for your use cases.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The era of On-Device AI is no longer a promise—it is a production reality. With the release of </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Gemini Nano v3</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we are placing unprecedented language understanding and multimodal capabilities directly into the palms of users. Through the Gemini Nano family of models, we have wide coverage of supported devices across the Android Ecosystem. But for developers building the next generation of intelligent apps, access to a powerful model is only step one. The real challenge lies in </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">customization</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: How do you tailor a foundation model to expert-level performance for your specific use case without breaking the constraints of mobile hardware?</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the server-side world, the larger LLMs tend to be highly capable and require less domain adaptation. Even when needed, more advanced options such as LoRA (Low-Rank Adaptation) fine-tuning can be feasible options. However, the unique architecture of Android AICore prioritizes a </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">shared, memory-efficient system model</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This means that deploying custom LoRA adapters for every individual app comes with challenges on these shared system services.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But there is an alternate path that can be equally impactful. By leveraging </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Automated Prompt Optimization (APO)</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> on Vertex AI, developers can achieve quality approaching fine-tuning, all while working seamlessly within the native Android execution environment. By focusing on superior system instruction, APO enables developers to tailor model behavior with greater robustness and scalability than traditional fine-tuning solutions.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span id="docs-internal-guid-5c954ba0-7fff-cdf3-65af-51fe569d5d6b"><span style="font-family: inherit;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Note: </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Gemini Nano V3 is a quality optimized version of the highly acclaimed </span><a href="https://developers.googleblog.com/en/introducing-gemma-3n/" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">Gemma 3N</span></a><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> model. Any prompt optimizations that are made on the open source Gemma 3N model will apply to Gemini Nano V3 as well. On </span><a href="https://developers.google.com/ml-kit/genai#prompt-device" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">supported devices</span></a><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, ML Kit GenAI APIs leverage the </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">nano-v3</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> model to maximize the quality for Android Developers</span></span></span></p><div><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4O-6TGBs-g06EHQHaDaoJRSlG5LrgeZfwGHwzBdM87LkbrQ0s6OZVD5J5SXufoy07KdcB10qIy7iAopssbt1fKJpPpWheSHdbETtg8Vyt9ZDn-Yy6xUhGl2WFkVe5LcR-6zhN-t3texV_arqoDIwmz8UlULlzmZ4M17uMBdraiJtEh_vRa4G8S3jGuDY/s960/APO%20block%20diagram.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="960" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4O-6TGBs-g06EHQHaDaoJRSlG5LrgeZfwGHwzBdM87LkbrQ0s6OZVD5J5SXufoy07KdcB10qIy7iAopssbt1fKJpPpWheSHdbETtg8Vyt9ZDn-Yy6xUhGl2WFkVe5LcR-6zhN-t3texV_arqoDIwmz8UlULlzmZ4M17uMBdraiJtEh_vRa4G8S3jGuDY/s16000/APO%20block%20diagram.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div></span></div></span></name></div><div><name content="IMG" twitter:image=""><span id="docs-internal-guid-a60a3ab8-7fff-6d1f-553d-9011b03e465a"><span style="font-family: inherit;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">APO treats the prompt not as a static text, but as a programmable surface that can be optimized. It leverages server-side models (like Gemini Pro and Flash) to propose prompts, evaluate variations and find the optimal one for your specific task. This process employs three specific technical mechanisms to maximize performance:</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="font-family: inherit;"><span id="docs-internal-guid-6685dd1c-7fff-204c-93e0-3bae18fad340"></span></span></p><ol style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; margin-left: -12pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Automated Error Analysis:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> APO analyzes error patterns from training data to Automatically identify specific weaknesses in the initial prompt.</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; margin-left: -12pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Semantic Instruction Distillation:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> It analyzes massive training examples to distill the "true intent" of a task, creating instructions that more accurately reflect the real data distribution.</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; margin-left: -12pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Parallel Candidate Testing:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Instead of testing one idea at a time, APO generates and tests numerous prompt candidates in parallel to identify the global maximum for quality.</span></span></p></li></ol><div><span style="color: #1f1f1f;"><span style="white-space-collapse: preserve;"><br /></span></span></div><div><span id="docs-internal-guid-638fae10-7fff-cef2-e426-75382acd45f1"><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit; font-size: x-large;">Why APO Can Approach Fine Tuning Quality</span></span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">It is a common misconception that fine-tuning always yields better quality than prompting. For modern foundation models like Gemini Nano v3, prompt engineering can be impactful by itself:</span></span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; margin-left: -12.75pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Preserving General capabilities:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Fine-tuning ( PEFT/LoRA) forces a model's weights to over-index on a specific distribution of data. This often leads to "catastrophic forgetting," where the model gets better at your specific syntax but worse at general logic and safety. APO leaves the weights untouched, preserving the capabilities of the base model.</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; margin-left: -12.75pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Instruction Following &amp; Strategy Discovery:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Gemini Nano v3 has been rigorously trained to follow complex system instructions. APO exploits this by finding the </span><span style="background-color: transparent; color: #1f1f1f; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">exact</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> instruction structure that unlocks the model's latent capabilities, often discovering strategies that might be hard for human engineers to find.&nbsp;</span></span></p></li></ul><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span id="docs-internal-guid-55aac14a-7fff-9bab-3900-ba14ee98dd83"><span style="font-family: inherit;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">To validate this approach, we evaluated APO across diverse production workloads. Our validation has shown consistent </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">5-8% accuracy gains</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> across various use cases.Across multiple deployed on-device features, APO provided significant quality lifts.</span></span></span></p><div dir="ltr" style="margin: 0px auto; width: fit-content;"></div><span style="font-family: inherit;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /><br /></span></span><p></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit; font-size: x-large;"><span id="docs-internal-guid-641026f9-7fff-7618-0512-c76ffd65aaad" style="font-weight: normal;"><div align="left" dir="ltr" style="margin-left: -20.25pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="152"></col><col width="125"></col><col width="125"></col><col width="125"></col><col width="125"></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Use Case</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Task Type</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Task Description</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Metric</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">APO Improvement</span></p></td></tr><tr style="height: 0pt;"><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Topic classification</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Text classification</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Classify a news article into topics such as finance, sports, etc</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Accuracy</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">+5%</span></p></td></tr><tr style="height: 0pt;"><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Intent classification</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Text classification</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Classify a customer service query into intents</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Accuracy</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">+8.0%</span></p></td></tr><tr style="height: 0pt;"><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Webpage translation</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Text translation</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Translate a webpage from English to a local language</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">BLEU</span></p></td><td style="background-color: #f8fafd; border-bottom: solid #000000 0.75pt; border-color: rgb(0, 0, 0); border-left: solid #000000 0.75pt; border-right: solid #000000 0.75pt; border-style: solid; border-top: solid #000000 0.75pt; border-width: 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 6pt 9pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: transparent; color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">+8.57%</span></p></td></tr></tbody></table></div></span></span></span></h2><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span style="color: #1f1f1f; font-family: inherit; font-size: xx-large; white-space-collapse: preserve;">A Seamless, End-to-End Developer Workflow</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">It is a common misconception that fine-tuning always yields better quality than prompting. For modern foundation models like Gemini Nano v3, prompt engineering can be impactful by itself:</span></span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; margin-left: -12.75pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Preserving General capabilities:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Fine-tuning ( PEFT/LoRA) forces a model's weights to over-index on a specific distribution of data. This often leads to "catastrophic forgetting," where the model gets better at your specific syntax but worse at general logic and safety. APO leaves the weights untouched, preserving the capabilities of the base model.</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; margin-left: -12.75pt; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Instruction Following &amp; Strategy Discovery:</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Gemini Nano v3 has been rigorously trained to follow complex system instructions. APO exploits this by finding the </span><span style="background-color: transparent; color: #1f1f1f; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">exact</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> instruction structure that unlocks the model's latent capabilities, often discovering strategies that might be hard for human engineers to find.&nbsp;</span></span></p></li></ul><p dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 0pt;"><span id="docs-internal-guid-55aac14a-7fff-9bab-3900-ba14ee98dd83"><span style="font-family: inherit;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">To validate this approach, we evaluated APO across diverse production workloads. Our validation has shown consistent </span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">5-8% accuracy gains</span><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> across various use cases.Across multiple deployed on-device features, APO provided significant quality lifts.</span></span></span></p></span></div></span></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><span id="docs-internal-guid-1f807f6a-7fff-57c8-bcf4-d94f6b2cb3a0"><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 6pt;"><span style="color: #1f1f1f; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit; font-size: large;">Conclusion</span></span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The release of </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Automated Prompt Optimization (APO)</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> marks a turning point for on-device generative AI. By bridging the gap between foundation models and expert-level performance, we are giving developers the tools to build more robust mobile applications. Whether you are just starting with </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Zero-Shot Optimization</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> or scaling to production with </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Data-Driven</span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> refinement, the path to high-quality on-device intelligence is now clearer.</span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Launch your on-device use cases to production today with ML Kit’s Prompt API and Vertex AI’s Automated Prompt Optimization.&nbsp;</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Relevant links:&nbsp;</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit;"><span id="docs-internal-guid-48074f87-7fff-43d7-102d-11786658c541"></span></span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 6pt;"><span style="font-family: inherit;"><a href="https://developers.google.com/ml-kit/genai/prompt/android/get-started" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">ML Kit Prompt API</span></a><span style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">,</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://cloud.google.com/vertex-ai/generative-ai/docs/learn/prompts/prompt-optimizer" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Vertex AI Prompt Optimizer documentation</span></span></a></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: #1f1f1f; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><a href="https://developers.googleblog.com/en/introducing-gemma-3n/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Gemma 3N Announcement Blog</span></span></a></p></li></ul><div><span face="&quot;Google Sans Text&quot;, sans-serif" style="color: #1f1f1f; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div></span></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div><div><name content="IMG" twitter:image=""><span style="font-family: inherit;"><br /></span></name></div>
28.01.2026 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
Beyond the smartphone: How JioHotstar optimized its UX for foldables and tablets <span style="font-family: inherit;"><i>Posted by Prateek Batra, Developer Relations Engineer, Android Adaptive Apps</i></span><name content="IMG" twitter:image=""><p></p></name><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxkdTthP8A7AMul1rBwU1dJgplW3Ckc2iwnD0K19coPlps-xHa4HcMJoo-6FqUFPCDBAERlTO0qZ4oduKoyBFxLvnY8FtyQ2JecKqJPt9l2rAA9U-LW4URdgB1Z5mWJcboiEq4QeMc8npaUl_v8ItwEDR76wQA3V6s3xgmFfki34hShzyHGSnlq755XzE/s8419/Beyond%20Phones%20How%20JioHotstar%20Built%20an%20Adaptive%20UX%20Blog%20.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="2507" data-original-width="8419" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxkdTthP8A7AMul1rBwU1dJgplW3Ckc2iwnD0K19coPlps-xHa4HcMJoo-6FqUFPCDBAERlTO0qZ4oduKoyBFxLvnY8FtyQ2JecKqJPt9l2rAA9U-LW4URdgB1Z5mWJcboiEq4QeMc8npaUl_v8ItwEDR76wQA3V6s3xgmFfki34hShzyHGSnlq755XzE/s16000/Beyond%20Phones%20How%20JioHotstar%20Built%20an%20Adaptive%20UX%20Blog%20.png" /></a></div><br /></div><div><br /></div><div><span style="font-family: inherit;"><span id="docs-internal-guid-220a4402-7fff-671c-c5c1-4665259d844c"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Beyond Phones: How JioHotstar Built an Adaptive UX</span></span></span></div><div><br /></div><div><a href="https://play.google.com/store/apps/details?id=in.startv.hotstar&amp;hl=en_IN" style="font-family: inherit; text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">JioHotstar</span></a><span style="background-color: white; color: #444746; font-family: inherit; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: white; font-family: inherit; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">is a leading streaming platform in India, serving a user base exceeding 400 million. With a vast content library encompassing over 330,000 hours of video on demand (VOD) and real-time delivery of major sporting events, the platform operates at a massive scale.</span></div><div><span style="font-family: inherit;"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: white; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">T</span><span style="background-color: white; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">o help ensure a premium experience for its vast audience, JioHotstar elevated the viewing experience by optimizing their app for foldables and tablets. They accomplished this by following Google’s adaptive app guidance and utilizing resources like</span><span style="background-color: white; color: #444746; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">&nbsp;</span><a href="https://developer.android.com/design/ui/large-screens/samples" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">samples</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><a href="https://github.com/android/large-screen-codelabs" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">codelabs</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><a href="https://developer.android.com/guide/topics/large-screens/large-screen-cookbook" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">cookbooks</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, and </span><a href="https://developer.android.com/guide/topics/large-screens" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">documentation</span></a><span style="background-color: white; color: #444746; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: white; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">to help create a consistently seamless and engaging experience across all display sizes.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: white; color: #444746; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: white; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span id="docs-internal-guid-64c03026-7fff-1bb2-a98a-9a93c53967f8"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-size: 18pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline;">JioHotstar's large screen challenge</span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: white; color: #444746; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span id="docs-internal-guid-f7c3fd7e-7fff-355d-78ff-eab6df19dbd9"></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JioHotstar offered an excellent user experience on standard phones and the team wanted to take advantage of new form factors. To start, the team evaluated their app against the </span><a href="https://developer.android.com/docs/quality-guidelines/large-screen-app-quality" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">large screen app quality guidelines</span></a><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to understand the optimizations required to extend their user experience to foldables and tablets. To achieve </span><a href="https://developer.android.com/docs/quality-guidelines/large-screen-app-quality?hl=en#tier_1_best_large_screen_differentiated" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Tier 1</span></a><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> large screen app status, the team implemented two strategic updates to adapt the app across various form factors and differentiate on foldables. By addressing the unique challenges posed by foldable and tablet devices, JioHotstar aims </span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">to deliver</span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a high-quality and immersive experience across all display sizes and aspect ratios.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-75f81b7f-7fff-b6db-2a79-cd5199bf2129"><span face="&quot;Google Sans&quot;, sans-serif" style="font-size: 18pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 600; vertical-align: baseline; white-space-collapse: preserve;">What they needed to do</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"><br /></span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-35690295-7fff-d426-4a6d-ded8dbc3d789"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">JioHotstar’s user interface, designed primarily for standard phone displays, encountered challenges in adapting hero image aspect ratios, menus, and show screens to the diverse screen sizes and resolutions of other form factors. This often led to image cropping, letterboxing, low resolution, and unutilized space, particularly in landscape mode. To help fully leverage the capabilities of tablets and foldables and deliver an optimized user experience across these device types, JioHotstar focused on refining the UI to ensure optimal layout flexibility, image rendering, and navigation across a wider range of devices.</span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"><br /></span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-45c30fe9-7fff-e408-7197-4293cfed2e1a"><span face="&quot;Google Sans&quot;, sans-serif" style="font-size: 18pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 600; vertical-align: baseline; white-space-collapse: preserve;">What they did</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span><span face="&quot;Google Sans&quot;, sans-serif" style="color: #3ddc84; font-size: 18pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 600; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt;"><span style="font-family: inherit; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">For a better viewing experience on large screens, JioHotstar took the initiative to enhance its app by incorporating </span><a href="https://developer.android.com/develop/ui/compose/layouts/adaptive/use-window-size-classes" style="font-family: inherit; text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">WindowSizeClass</span></a><span style="font-family: inherit; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> and creating optimized layouts for compact, medium and extended widths. This allowed the app to adapt its user interface to various screen dimensions and aspect ratios, ensuring a consistent and visually appealing UI across different devices.</span></p></span><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span id="docs-internal-guid-5f6d2eb9-7fff-fa4c-4f36-255526a935a8"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">JioHotstar followed this pattern using Material 3 Adaptive library to know how much space the app has available. First invoking the</span></span></span><span><span face="&quot;Google Sans&quot;, sans-serif" style="font-family: inherit; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span></span></span><span id="docs-internal-guid-13cbb1fc-7fff-3ea0-4aff-5af0ca3ce1f4"><a href="https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/package-summary#currentWindowAdaptiveInfo(kotlin.Boolean)" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">currentWindowAdaptiveInfo()</span></span></a></span><span id="docs-internal-guid-30bd9ab3-7fff-9940-b3a9-52599c6ffeed"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"> </span>function</span></span></span><span style="font-family: inherit;">, </span><span style="font-family: inherit;"><span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">then using new layouts accordingly for the three window size classes:</span></span></span></span></p><span style="font-family: inherit;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"><br /></span></span></span></p><pre style="color: #333333; line-height: 16.25px; margin: 0px;"><span style="color: blue;">val</span> sizeClass = currentWindowAdaptiveInfo().windowSizeClass <span style="color: blue;">if</span>(sizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND)) { showExpandedLayout() } <span style="color: blue;">else</span> <span style="color: blue;">if</span>(sizeClass.isHeightAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND)) { showMediumLayout() } <span style="color: blue;">else</span> { showCompactLayout() }<br /></pre><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 12pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The breakpoints are in order, from the biggest to the smallest, as internally the API checks for with a greater or equal then, so any width that is at least greater or equal then </span><span style="background-color: transparent; color: #188038; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">EXPANDED</span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> will always be greater than </span><span style="background-color: transparent; color: #188038; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">MEDIUM</span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 12pt;"><span id="docs-internal-guid-08ca4571-7fff-bc2a-dd7f-20660ca00457"><span style="font-family: inherit;"><br /><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">JioHotstar is able to provide the premium experience unique to foldable devices: </span><span id="docs-internal-guid-74bb3cf1-7fff-526d-abb0-dba9002e9e45"><a href="https://developer.android.com/develop/ui/compose/layouts/adaptive/foldables/make-your-app-fold-aware#tabletop_posture" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">Tabletop Mode</span></span></a></span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">.</span> This feature conveniently relocates the video player to the top half of the screen and the video controls to the bottom half when a foldable device is partially folded for a handsfree experience.</span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 12pt;"><span><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"></span></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dztTmrP-AMhhzkEv2TdcT3UWv4Or_MKMZ0yuiOf1DOoyc8PlqedhoR2IXXf7SXKxc6O_oHYuaEiNWbYEblA5A' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div></span></div><div style="text-align: left;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"><br /></span></span></span></div><div><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">To accomplish this, also using the Material 3 Adaptive library, the same </span></span></span><span id="docs-internal-guid-0020e610-7fff-17c4-638e-421605d5fdc0"><a href="https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/Posture#isTabletop()" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">currentWindowAdaptiveInfo()</span></span></a></span><span style="font-family: inherit;"><span style="font-family: inherit;"> </span>can</span><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"> be used to query for the tabletop mode. Once the device is held in tabletop mode, a change of layout to match the top and bottom half of the posture can be done with a column to place the player in the top half and the controllers in the bottom half:</span></span></span></div><div><span style="white-space-collapse: preserve;"><br /></span><span style="font-family: inherit;"><pre style="color: #333333; line-height: 16.25px; margin: 0px;"><span style="color: blue;">val</span> isTabletTop = currentWindowAdaptiveInfo().windowPosture.isTabletop <span style="color: blue;">if</span>(isTabletopMode) { Column { Player(Modifier.weight(1f)) Controls(Modifier.weight(1f)) } } <span style="color: blue;">else</span> { usualPlayerLayout() }</pre><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-a8b0f8c2-7fff-2815-1358-989526214405"></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-707771a4-7fff-5162-acae-bb0647b3758b"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">JioHotstar is now meeting the </span><a href="https://developer.android.com/docs/quality-guidelines/large-screen-app-quality" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">Large Screen app quality guidelines</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> for Tier 1. The team leveraged </span><a href="https://developer.android.com/adaptive-apps" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">adaptive app</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> guidance, utilizing </span><a href="https://developer.android.com/design/ui/large-screens/samples" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">samples</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><a href="https://github.com/android/large-screen-codelabs" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">codelabs</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><a href="https://developer.android.com/guide/topics/large-screens/large-screen-cookbook" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">cookbooks</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">, and </span><a href="https://developer.android.com/guide/topics/large-screens" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">documentation</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> to incorporate these recommendations.</span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;"><b id="docs-internal-guid-e7c70eec-7fff-5537-efd0-a05b1fe5dd99" style="font-weight: normal;"><br /></b></span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-9df7aa2e-7fff-3c4f-b174-d84418a709dc"></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span id="docs-internal-guid-664aeea6-7fff-eed6-835d-a1f7ddcfe0a2"></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">To further improve the user experience, JioHotstar increased touch target sizes, to the recommended 48dp, on video discovery pages, ensuring accessibility across large screen devices. Their video details page is now adaptive, adjusting to screen sizes and orientations. They moved beyond simple image scaling, instead leveraging window size classes to detect window size and density in real time and load the most appropriate hero image for each form factor, helping to enhance visual fidelity. Navigation was also improved, with layouts adapting to suit different screen sizes.</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;"><br /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Now users can view their favorite content from JioHotstar on large screens devices with an improved and highly optimized viewing experience.</span></span></p><p style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;"><span id="docs-internal-guid-87b0ce7b-7fff-992e-0fcd-2ac73366b01f"></span></span></span></p><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></p><blockquote><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Achieving Tier 1 large screen app status with Google is a milestone that reflects the strength of our shared vision. At JioHotstar, we have always believed that optimizing for large screen devices goes beyond adaptability, it’s about elevating the viewing experience for audiences who are rapidly embracing foldables, tablets, and connected TVs.</span></p><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-f2b4d23f-7fff-b4ba-6dca-f1972de0d851"></span></span></p><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Leveraging Google's Jetpack libraries and guides allowed us to combine our insights on content consumption with their expertise in platform innovation. This collaboration allowed both teams to push boundaries, address gaps, and co-create a seamless, immersive experience across every screen size.</span></p><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Together, we’re proud to bring this enhanced experience to millions of users and to set new benchmarks in how India and the world experience streaming.</span></p><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span id="docs-internal-guid-46e5d24c-7fff-d718-dda6-249ac7912035"></span></p><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Sonu Sanjeev</span><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Senior Software Development Engineer</span></p></blockquote><p style="line-height: 1.38; margin-bottom: 12pt; margin-top: 12pt; text-align: left;"><span face="&quot;Google Sans&quot;, sans-serif" style="background-color: transparent; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></p></span></div>
27.01.2026 03:30 👍 0 🔁 0 💬 0 📌 0
Preview
Trade-in mode on Android 16+ <name content="IMG" twitter:image=""><p><span style="font-family: inherit;"></span></p><h4 style="text-align: left; white-space-collapse: preserve;"><b style="font-size: x-large;"><i>Supporting Longevity through Faster Diagnostics</i></b></h4><p><span style="font-family: inherit;"><i>Posted by&nbsp;<span style="white-space-collapse: preserve;">Rachel S, Android Product Manager</span></i></span></p><p><span style="font-family: inherit;"><i></i></span></p><div class="separator" style="clear: both; text-align: center;"><span style="font-family: inherit;"><i><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6Aq4lb9qsSAAh7hBxqYjCIYImJREOYZUqPO7yYdvbr-81VWa3lPQdkT-ekLr3Xd-YBWbEShGKr0fuYMoW0skg_vtHrzQxYf42jUqkAgqwo-11igWWNa_gxW-Rpb1TJAGgeumE0LjzoJej8efMSW6Ce7mUmaA0x_n6RxG6-5SpYQYIofO7bRF31J2v4wI/s4209/Android_TradeIN_Mode_Blog.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1253" data-original-width="4209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6Aq4lb9qsSAAh7hBxqYjCIYImJREOYZUqPO7yYdvbr-81VWa3lPQdkT-ekLr3Xd-YBWbEShGKr0fuYMoW0skg_vtHrzQxYf42jUqkAgqwo-11igWWNa_gxW-Rpb1TJAGgeumE0LjzoJej8efMSW6Ce7mUmaA0x_n6RxG6-5SpYQYIofO7bRF31J2v4wI/s16000/Android_TradeIN_Mode_Blog.png" /></a></i></span></div><span style="font-family: inherit;"><span style="font-family: inherit; white-space-collapse: preserve;"><p style="font-style: italic;"><i style="font-family: inherit;">Trade-in mode: faster assessment of a factory-reset phone or tablet, bypassing setup wizard, a new feature on Android 16 and above.</i></p><h3 style="text-align: left;"><span style="font-family: inherit; font-size: x-large;">Supporting device longevity</span></h3></span></span><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">Android is committed to making devices last longer. With device longevity comes device circularity: phones and tablets traded-in and resold. <span style="font-family: inherit;"><a href="https://www.gsma.com/solutions-and-impact/connectivity-for-good/external-affairs/climate-action/rethinking-mobile-phones/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">GSMA reported</span></a><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> that secondhand phones have around 80-90% lower carbon emissions than new phones. The secondhand device market has grown substantially both in volume and value, a trend projected to continue.</span></span></p><p><span id="docs-internal-guid-7ebb36e1-7fff-1fb1-9f1b-742bf18d2765"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline;"><span style="font-family: inherit;">Android 16 and above offers an easy way to access device information on any factory reset phone or tablet via the new </span><span style="color: #188038; font-family: Roboto Mono, monospace;"><span style="font-size: 10pt; white-space-collapse: preserve;">tradeinmode </span></span></span></span><span><span style="font-family: inherit;">parameter, accessed via adb commands. This means you can view quality indicators of a phone or tablet, skipping each setup wizard step. Simply connect a phone or tablet with adb, and use&nbsp;</span><span style="color: #188038; font-family: &quot;Roboto Mono&quot;, monospace; font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">tradeinmode</span><span face="&quot;Google Sans&quot;, sans-serif" style="font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="font-family: inherit;"><a href="https://androidsource.devsite.corp.google.com/docs/core/perf/trade-in-mode" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">commands</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span></span></span><span style="font-family: inherit;">to get information about the device.</span></p><p><span id="docs-internal-guid-aaa80139-7fff-cde7-5ee4-78a7e10ff168"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit; font-size: large;">Trade-in mode: What took minutes, now takes seconds </span></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Faster trade-in processing – </span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">By bypassing setup wizard, trade-in mode improves device trade ins. The mode enables immediate access to understand the ‘health’ of a device, helping everyone along the secondhand value chain check the quality of devices that are wiped. We’ve already seen significant increases in processing secondhand Android devices!&nbsp;</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Secure evaluation </span><span style="font-weight: 700; white-space-collapse: preserve;">– </span><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To ensure the device information is only accessed in secure situations, the device must 1) be factory reset, 2) not have cellular service, 3) not have connectivity or a connected account, and 4) be running a non-debuggable build.</span></span></p><p><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">Get device health information with one command – </span></span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">You can view all the below device information with adb command from your workstation</span> </span></span><span style="color: #188038; font-family: &quot;Roboto Mono&quot;, monospace; font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">adb shell tradeinmode getstatus</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">, skipping setup wizard:&nbsp;</span></span></p><p></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device information&nbsp;</span></span></p></li><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device IMEI(s)&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device serial number&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Brand&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Model&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Manufacturer&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device model, e.g., Pixel 9</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device brand, e.g., Google</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device manufacturer, e.g., Google</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Device name, e.g., tokay</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">API level to ensure correct OS version, e.g., launch_level : 34</span></span></p></li></ul><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Battery heath&nbsp;</span></span></p></li><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Cycle count</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Health</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">State, e.g., unknown, good, overheat, dead, over_voltage, unspecified_failure, cold, fair, not_available, inconsistent</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Battery manufacturing date&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Date first used&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Serial number (to help provide indication of genuine parts, if OEM supported)</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Part status, e.g., replaced, original, unsupported</span></span></p></li></ul><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Storage&nbsp;</span></span></p></li><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Useful lifetime remaining&nbsp;</span></span></p></li><li aria-level="2" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Total capacity&nbsp;</span></span></p></li></ul><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Screen Part status, e.g., replaced, original, unsupported</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Foldables (number of times devices has been folded and total fold lifespan)&nbsp;</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Moisture intrusion&nbsp;</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">UICCS information i.e., Indication if there is an e-SIM or removable SIM and the microchip ID for the SIM slot</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Camera count and location, e.g., 3 cameras on front and 2 on back</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: inherit;">Lock detection for select device locks</span></span></p></li><li aria-level="1" dir="ltr" style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And the list keeps growing! Stay up to date </span><a href="https://androidsource.devsite.corp.google.com/docs/core/perf/trade-in-mode" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.&nbsp;</span></span></p></li></ul><div><span style="white-space-collapse: preserve;"><br /></span></div><div><span id="docs-internal-guid-97633792-7fff-687e-131b-86e29c702b30"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Run your own tests – </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Trade-in mode enables you to run your own diagnostic commands or applications by entering the evaluation flow using </span></span><span style="color: #188038; font-family: &quot;Roboto Mono&quot;, monospace; font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">tradeinmode evaluate</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">. The device will automatically factory reset on reboot after evaluation mode to ensure nothing remains on the device.&nbsp;</span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Ensure the device is running an approved build – </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Further, when connected to the internet, with a single command </span></span><span style="color: #188038; font-family: &quot;Roboto Mono&quot;, monospace; font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">tradeinmode getstatus --challenge</span><span face="&quot;Google Sans&quot;, sans-serif" style="font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span face="&quot;Google Sans Text&quot;, sans-serif" style="background-color: white; color: #d01884; font-size: 10pt; font-style: italic; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">CHALLENGE</span><span face="&quot;Google Sans&quot;, sans-serif" style="font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="font-family: inherit;">you can test the device’s operating system (OS) authenticity, to be sure the device is running a trusted build. If the build passes the test, you can be sure the diagnostics results are coming from a trusted OS.&nbsp;</span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">There’s more</span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"> – You can use commands to factory reset, power off, reboot, reboot directly into trade-in mode, check if trade-in mode is active, revert to the previous mode, and pause tests until system services are ready.&nbsp;</span></span></p><span style="font-family: inherit;"><br /></span><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: inherit;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">Want to try it? </span><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">Learn more about the </span><a href="https://source.android.com/docs/core/perf/trade-in-mode" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">developer steps and commands</span></a><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;">.&nbsp;</span></span></p><div><span face="&quot;Google Sans&quot;, sans-serif" style="font-size: 10pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div></span></div><p></p></name>
26.01.2026 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
Ready to review some changes but not others? Try using Play Console’s new Save for later feature _Posted by Georgia Doyle, Senior UX Writer and Content Designer,__and_ _Kanu Tibrewal, Software Engineer_ We’ve launched a new Save for later feature on Google Play Console’s Publishing overview to give you more control over when you send changes for review. In the past, changes to your app were bundled together before being sent for review. This presented challenges if you needed to reprioritize changes, or if the changes were no longer relevant. For example, updates to your test tracks grouped with marketing changes that need to be rescheduled. This lack of flexibility meant that if some changes were ready for review but not others, you could end up delaying urgent fixes, or publishing changes that you weren’t quite ready to make. Now, you have the ability to hold back the changes you’re not ready to have reviewed. How it works In the 'Changes not yet sent for review' section of the Publishing overview page, select ‘Save for later’ on the groups of changes that you don’t want to include in your next review. You can view and edit the list of saved changes, and return them to the Publishing overview if you change your mind. Once the review has started, your saved changes will be added back to ‘Changes not yet sent for review’. **Integration with our pre-review checks** Save for later also works with our pre-review checks. Pre-review checks look for issues in your changes that may prevent your app from being published, so that you can fix them before you send changes for review. If checks find issues with your app, there are two ways you can proceed: * If issues are isolated to an individual track, we’ll show you an error beside that change, so you know what to save for later in order to proceed to review with your other changes. * If you have issues that affect your whole app, for example, App content issues, Save for later will be unavailable and you will need to fix them before you can send any changes for review. **Greater flexibility in your workflows** Our goal for Save for later is to give you greater flexibility over your release schedule. With this feature you can manage what changes you send for review, and address issues affecting individual tracks without holding up ready-to-release changes, so you can iterate faster and minimize the impact of rejections on your release timeline. **So, what's next?** We're committed to continuously improving your publishing experience. Save for later is a significant step towards providing you with more granular control over this all-important stage in the journey to publishing your app. We'll continue to gather your feedback and look at ways we can provide greater flexibility to the review and publishing process. We're excited to see how Save for later helps you to streamline your release process and bring your app innovations to users even faster.
21.01.2026 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
LLM flexibility, Agent Mode improvements, and new agentic experiences in Android Studio Otter 3 Feature Drop Posted by Sandhya Mohan, Senior Product Manager and Trevor Johns, Developer Relations Engineer We are excited to announce that Android Studio Otter 3 Feature Drop is now stable! This feature-packed release brings a huge update to your agentic workflows in Android Studio, and offers you more flexibility and control for how you use AI to help you build Android apps. * Bring Your Own Model: You can now use any LLM to power the AI functionality in Android Studio. * Agent Mode Enhancements: You can now more easily have Agent Mode interact with your app on devices, review and accept suggested changes, and have multiple conversations threads. * Run user journey tests using natural language: with Journeys in Android Studio. * Enable Agent Mode to connect to more tools: including the ability to connect to remote servers via MCP. * Build, iterate and test your UI: with UI agentic experiences in Android Studio. * Build deep links using natural language: with the new app links assistant. * Debug R8 optimized code: with Automatic Logcat retracing. * **Simplify Android library modules:** with the Fused library plugin. Here’s a deep dive into what’s new: ### Bring Your Own Model (BYOM) Every developer has a unique workflow when using AI, and different companies have different policies on AI model usage. With this release, Android Studio now brings you more flexibility by allowing you to choose the LLM that powers the AI functionality in Android Studio, giving you more control over performance, privacy, and cost. #### Use a remote model You can now integrate remote models—such as OpenAI’s GPT, Anthropic’s Claude, or a similar model—directly into Android Studio. This allows you to leverage your preferred model provider without changing your IDE. To get started, configure a remote model provider in Settings by adding your API endpoint and key. Once configured, you can select your custom model directly from the picker in the AI chat window. Enter the remote model provider information. #### Use a local model If you have limited internet connectivity, strict data privacy requirements, or a desire to experiment with open-source research, Android Studio now supports local models via providers like LM Studio or Ollama. While Gemini in Android Studio remains the default recommendation—tuned specifically for Android development with full context awareness—if you have a specific model preference, Android Studio supports it. Model picker in Android Studio. A local model offers an alternative to the LLM support built into Android Studio, and typically requires significant local system RAM and hard drive space to run well. However, Gemini in Android Studio provides the best Android development experience because Gemini is tuned for Android and supports all features of Android Studio. With Gemini, you can choose from a variety of models for your Android development tasks, including the no-cost default model or models accessed with a paid Gemini API key. #### Use your Gemini API key While Android Studio includes access to a default Gemini model with generous quotas at no cost, some developers need more. By adding your Gemini API key, Android Studio can directly access all the latest Gemini models available from Google. ** ** For example, this allows you to use the most recent Gemini 3 Pro and Gemini 3 Flash models (among others) with expanded context windows and quota. This is especially useful for developers who are using Agent Mode for extended coding sessions, where this additional processing power can provide higher fidelity responses. You can also read more about how we're rolling out Gemini 3 to all Android Studio users, including Gemini Code Assist subscribers and developers accessing the default Gemini in Android Studio model at no-cost. ### Agent Mode enhancements Agent Mode is the semi-autonomous AI assistant in Android Studio that aids in your software development, used by many developers, including the Ultrahuman team. Get more out of Agent Mode with these new updates. #### Run your app and interact with it on devices Agent Mode can now deploy an application to the connected device, inspect what is currently shown on the screen, take screenshots, check Logcat for errors, and interact with the running application. This lets the agent help you with changes or fixes that involve re-running the application, checking for errors, and verifying that a particular update was made successfully (for example, by taking and reviewing screenshots). Agent mode uses device actions to deploy and verify changes. #### Find and review changes using the changes drawer You can now see and manage all changes made by the AI agent using the changes drawer. When the agent makes changes to your codebase, you can see the files that were edited in Files to review. From there, you can keep or revert the changes individually or all together. Click an individual file in the drawer to see the code diff in the editor and make refinements if needed. With the changes drawer, you can keep track of edits made by the agent during your chat and revisit specific changes without scrolling back through your conversation history. _See all the files that the agent has proposed edits to in the changes drawer._ Note: If the Don't ask to edit files setting is disabled in Agent Options , Agent Mode will request permission for every individual change. Each change must be accepted before it appears in the changes drawer. To allow multiple file edits to appear in the drawer simultaneously, enable the Don't ask to edit files option. Accept a change to add it to the changes drawer. #### Manage multiple conversation threads You can now organize your conversations with Gemini in Android Studio into multiple threads. This lets you create a new chat or agent thread when you need to start with a clean slate, and you can go back to older conversations in the history tab. Using separate threads for each distinct task can improve response quality by limiting the scope of the AI's context to only the topic at hand. To start a new thread, click New Conversation . To see your conversation history, click Recent Chats. See prior conversations in the “Recent Chats” tab. Your conversation history is saved to your account, so if you have to sign out or switch accounts you can resume right where you left off when you come back. ### Journeys for Android Studio Running end-to-end UI tests can improve confidence that you’re shipping a high-quality app to production, but writing and maintaining those tests can be difficult, brittle, and limited in what you’re able to test. Journeys for Android Studio leverages the reasoning and vision capabilities of Gemini to enable you to write and maintain end-to-end UI tests using natural language instructions—and it’s now available in the latest stable release of Android Studio when you enable it from Studio Labs in your Android Studio Settings. Journeys for Android Studio. These natural language instructions are converted into interactions that Gemini performs directly on your app. This not only makes your tests easier to write and understand, but also enables you to define complex assertions that Gemini evaluates based on what it “sees” on the device screen. Because Gemini reasons about how to achieve your goals, these tests are more resilient to subtle changes in your app's layout, significantly reducing flaky tests when running against different app versions or device configurations. Journeys for Android Studio. _ _ You can write and run journeys directly from Android Studio against any local or remote device. The IDE provides a new editor experience for crafting your test steps in an XML file, using either a code view or a dedicated design view. When you run a journey, Android Studio provides rich, detailed results that help you follow Gemini's execution. The test panel breaks down the entire journey into its discrete steps, showing you screenshots for each action, what action was taken, and Gemini's reasoning for why it took that action, making debugging and validation clearer than ever. And because journeys are run as Gradle tasks, you can run them from the command line after you authenticate with a Google Cloud Project. ### Support for remote MCP servers Android Studio now lets you connect directly to remote Model Context Protocol (MCP) servers such as Figma, Notion, Canva, Linear, and more. This significantly reduces your context switching since it enables the AI agent in Android Studio to leverage external tools, helping you stay in your flow. For example, you can connect to Figma's remote MCP server to access files and provide this information to Agent Mode, generating more accurate code from your designs. To learn more about how to add an MCP server, see Add an MCP server. Connect to the Figma remote MCP server in Android Studio Settings. Quickly add a screen to your app using the Figma remote MCP server. ### Supercharge your UI development with Agent Mode Gemini in Android Studio is now integrated into the UI development workflow directly from within the Compose Preview panel, helping you go from design to a high-quality implementation faster. These new agentic capabilities are designed to assist you at every stage of development, from initial code generation to iteration, refinement, and debugging, with entry points in the context of your work. #### Create new UI from a design mock Accelerate your initial UI implementation by generating Compose code directly from a design mock. Simply click Generate Code From Screenshot in an empty Preview panel, and Gemini will use the image to generate a starting implementation, saving you from writing boilerplate from scratch. Generate code from a screenshot in an empty Preview panel. Example turning design into Compose code. #### #### Match your UI with a target image Once you have an initial implementation, you can iteratively refine it to be pixel-perfect. Right-click your Compose Preview and select AI Actions > Match UI to Target Image. Upload a reference design, and the agent will suggest code changes to make your UI match the design as closely as possible. Example of using "Match UI to Target Image" #### Iterate on your UI with natural language For more specific or creative changes, right-click on your preview and use the AI Actions >  Change UI. This capability now leverages Agent Mode to validate the results, making it more powerful and accurate. You can use natural language prompts like "change the button color to blue" or "add padding around this text," and Gemini will apply the code modifications instantly. Example of using "Change UI" **Find and fix UI quality issues** Verifying your UI is high-quality and more accessible is a critical final step. The AI Actions > Fix all UI check tool audits your UI for common problems, such as accessibility issues. The agent will then propose and apply fixes to resolve the detected issues. Entry point to trigger "Fix all UI check issues" You can also find the same functionality by using the Fix with AI button in Compose UI check mode: "Fix with AI" in UI Check mode The features mentioned above are also accessible by the toolbar icon in the Preview panel: Second entry point to UI development AI features Beyond iterating on your UI, Gemini also helps streamline your development environment. To accelerate your setup, you can: * Generate Compose Previews: This feature is now enhanced by Agent Mode to provide more accurate results. When working in a file that has Composable functions but no @Preview annotations, you can right-click on the Composable and select Gemini > Generate [Composable name] Preview. The agent will now better analyze your Composable to generate the necessary boilerplate with correct parameters, to help verify that a successfully rendered preview is added. Entry point to generate Compose Preview * Fix Preview rendering errors: When a Compose Preview fails to render, Gemini can now analyze the error message and your code to find the root cause and apply a fix. Using "Fix with AI" on Preview render error ### App Links Assistant The App Links Assistant now integrates with Agent Mode to automate the creation of deep link logic, simplifying one of the most time-consuming steps of implementation. Instead of manually writing code to parse incoming intents and navigate users to the correct screen, you can now let Gemini generate the necessary code and tests. Gemini presents a diff view of the suggested code changes for your review and approval, streamlining the process of handling deep links and ensuring users are seamlessly directed to the right content in your app. To get started, open the App Links Assistant through the tools menu, then choose **Create Applink**. In the second step, **Add logic to handle the intent** , select **Generate code with AI assistance**. If a sample URL is available, enter it, and then click **Insert Code**. _App Links Assistant_ ### Automatic Logcat Retracing Debugging R8-optimized code just became seamless. Previously, when R8 was enabled (minifyEnabled = true in your build.gradle.kts file), it would obfuscate stack traces, changing class names, methods, and line numbers. To find the source of a crash, developers had to manually use the R8 retrace command line tool. Starting with Android Studio Otter 3 **Feature Drop** with AGP versions 8.12 and above, this extra step is no longer necessary. Logcat now automatically detects and retraces R8-processed stack traces, so you can see the original, human-readable stack trace directly in the IDE. This provides a much-improved debugging experience with no extra work required. _Logcat now automatically detects and retraces R8-processed stack traces_ ### Fused Library Plugin: Publish multiple Android libraries as one The new Fused Library plugin bundled with Android Gradle Plugin 9.0 allows you to package multiple Android library modules into a single, publishable Android Library (AAR). This was one of the most requested features for Android Gradle Plugin, and we are making it available for you today. This plugin enables you to modularize your code and resources internally while simplifying the integration process for your users by exposing only a single dependency. In addition to streamlining project setup and version management, distributing a fused library can help reduce library size through improved code shrinking and offer better control over your internal implementation details. To learn more about the Fused Library plugin see Publish multiple Android libraries as one with Fused Library. ### Get started Ready to dive in and accelerate your development? Download Android Studio Otter 3 Feature Drop and start exploring these powerful new features today! As always, your feedback is crucial to us. Check known issues, report bugs, and be part of our vibrant community on LinkedIn, Medium, YouTube, or X. Let's build the future of Android apps together!
15.01.2026 14:00 👍 1 🔁 0 💬 0 📌 0
Preview
Ultrahuman launches features 15% faster with Gemini in Android Studio _Posted by Amrit Sanjeev, Developer Relations Engineer and Trevor Johns, Developer Relations Engineer_ Ultrahuman is a consumer health-tech startup that provides daily well-being insights to users based on biometric data from the company’s wearables, like the RING Air and the M1 Live Continuous Glucose Monitor (CGM). The Ultrahuman team leaned on Gemini in Android Studio's contextually aware tools to streamline and accelerate their development process. Ultrahuman’s app is maintained by a lean team of just eight developers. They prioritize building features that their users love, and have a backlog of bugs and needed performance improvements that take a lot of time. The team needed to scale up their output of feature improvements, and also needed to handle their performance improvements, without increasing headcount. One of their biggest opportunities was reducing the amount of time and effort for their backlog: every hour saved on maintenance could be reinvested into working on features for their users. Solving technical hurdles and boosting performance with Gemini The team integrated Gemini in Android Studio to see if the AI enhanced tools could improve their workflow by handling many Android tasks. First, the team turned to the Gemini chat inside Android Studio. The goal was to prototype a GATT Server implementation for their application’s Bluetooth Low Energy (BLE) connectivity. As Ultrahuman’s Android Development Lead, Arka, noted, “Gemini helped us reach a working prototype in under an hour—something that would have otherwise taken us several hours.” The BLE implementation provided by Gemini worked perfectly for syncing large amounts of health sensor data while the app ran in the background, improving the data syncing process and saving battery life on both the user's Android phone and Ultrahuman's paired wearable device. Beyond this core challenge, Gemini also proved invaluable for finding algorithmic optimizations in a custom open-source library, pointing to helpful documentation, assisting with code commenting, and analyzing crash logs. The Ultrahuman team also used code completion to help them breeze through writing otherwise repetitive code, Jetpack Compose Preview Generation to enable rapid iteration during UI design, and Agent Mode for managing complex, project-wide changes, such as rendering a new stacked bar graph that mapped to backend data models and UI models. Transforming productivity and accelerating feature delivery These improvements have saved the team dozens of hours each week. This reclaimed time is being used to deliver new features to Ultrahuman’s beta users 10-15% faster. For example, the team built a new in-app AI assistant for users, powered by Gemini 2.5 Flash. The UI design, architecture, and parts of the user experience for this new feature were initially suggested by Gemini in Android Studio—showcasing a full-circle AI-assisted development process. Accelerate your Android development with Gemini Gemini's expert Android advice, closely integrated throughout Android Studio, helps Android developers spend less time digging through documentation and writing boilerplate code—freeing up more time to innovate. Learn how Gemini in Android Studio can help your team resolve complex issues, streamline workflows, and ship new features faster.
08.01.2026 22:00 👍 0 🔁 0 💬 0 📌 0
Preview
Media3 1.9.0 - What’s new _Posted by Kristina Simakova, Engineering Manager_ _ _ _ _ ### Media3 1.9.0 – What's new? Media3 1.9.0 is out! Besides the usual bug fixes and performance improvements, the latest release also contains **four** new or largely rewritten modules: * media3-inspector - Extract metadata and frames outside of playback * media3-ui-compose-material3 - Build a basic Material3 Compose Media UI in just a few steps * media3-cast - Automatically handle transitions between Cast and local playbacks * media3-decoder-av1 - Consistent AV1 playback with the rewritten extension decoder based on the dav1d library We also added caching and memory management improvements to PreloadManager, and provided several new ExoPlayer, Transformer and MediaSession simplifications. This release also gives you the first experimental access to CompositionPlayer to preview media edits. Read on to find out more, and as always please check out the full release notes for a comprehensive overview of changes in this release. ### Extract metadata and frames outside of playback There are many cases where you want to inspect media without starting a playback. For example, you might want to detect which formats it contains or what its duration is, or to retrieve thumbnails. The new media3-inspector module combines all utilities to inspect media without playback in one place: * MetadataRetriever to read duration, format and static metadata from a MediaItem. * FrameExtractor to get frames or thumbnails from an item. * MediaExtractorCompat as a direct replacement for the Android platform MediaExtractor class, to get detailed information about samples in the file. MetadataRetriever and FrameExtractor follow a simple AutoCloseable pattern. Have a look at our new guide pages for more details. suspend fun extractThumbnail(mediaItem: MediaItem) { FrameExtractor.Builder(context, mediaItem).build().use { val thumbnail = frameExtractor.getThumbnail().await() } } ### Build a basic Material3 Compose Media UI in just a few steps In previous releases we started providing connector code between Compose UI elements and your Player instance. With Media3 1.9.0, we added a new module media3-ui-compose-material3 with fully-styled Material3 buttons and content elements. They allow you to build a media UI in just a few steps, while providing all the flexibility to customize style. If you prefer to build your own UI style, you can use the building blocks that take care of all the update and connection logic, so you only need to concentrate on designing the UI element. Please check out our extended guide pages for the Compose UI modules. We are also still working on even more Compose components, like a prebuilt seek bar, a complete out-of-the-box replacement for PlayerView, as well as subtitle and ad integration. @Composable fun SimplePlayerUI(player: Player, modifier: Modifier = Modifier) { Column(modifier) { ContentFrame(player) // Video surface and shutter logic Row (Modifier.align(Alignment.CenterHorizontally)) { SeekBackButton(player) // Simple controls PlayPauseButton(player) SeekForwardButton(player) } } } Simple Compose player UI with out-of-the-box elements ### Automatically handle transitions between Cast and local playbacks The CastPlayer in the media3-cast module has been rewritten to automatically handle transitions between local playback (for example with ExoPlayer) and remote Cast playback. When you set up your MediaSession, simply build a CastPlayer around your ExoPlayer and add a MediaRouteButton to your UI and you're done! // MediaSession setup with CastPlayer val exoPlayer = ExoPlayer.Builder(context).build() val castPlayer = CastPlayer.Builder(context).setLocalPlayer(exoPlayer).build() val session = MediaSession.Builder(context, player) // MediaRouteButton in UI @Composable fun UIWithMediaRouteButton() { MediaRouteButton() } New CastPlayer integration in Media3 session demo app ### Consistent AV1 playback with the rewritten extension based on dav1d The 1.9.0 release contains a completely rewritten AV1 extension module based on the popular dav1d library. As with all extension decoder modules, please note that it requires building from source to bundle the relevant native code correctly. Bundling a decoder provides consistency and format support across all devices, but because it runs the decoding in your process, it's best suited for content you can trust. ### Integrate caching and memory management into PreloadManager We made our PreloadManager even better as well. It already enabled you to preload media into memory outside of playback and then seamlessly hand it over to a player when needed. Although pretty performant, you still had to be careful to not exceed memory limits by accidentally preloading too much. So with Media3 1.9.0, we added two features that makes this a lot easier and more stable: 1. Caching support – When defining how far to preload, you can now choose PreloadStatus.specifiedRangeCached(0, 5000) as a target state for preloaded items. This will add the specified range to your cache on disk instead of loading the data to memory. With this, you can provide a much larger range of items for preloading as the ones further away from the current item no longer need to occupy memory. Note that this requires setting a Cache in DefaultPreloadManager.Builder. 2. Automatic memory management – We also updated our LoadControl interface to better handle the preload case so you are now able to set an explicit upper memory limit for all preloaded items in memory. It's 144 MB by default, and you can configure the limit in DefaultLoadControl.Builder. The DefaultPreloadManager will automatically stop preloading once the limit is reached, and automatically releases memory of lower priority items if required. ### Rely on new simplified default behaviors in ExoPlayer As always, we added lots of incremental improvements to ExoPlayer as well. To name just a few: * Mute and unmute – We already had a setVolume method, but have now added the convenience mute and unmute methods to easily restore the previous volume without keeping track of it yourself. * Stuck player detection – In some rare cases the player can get stuck in a buffering or playing state without making any progress, for example, due to codec issues or misconfigurations. Your users will be annoyed, but you never see these issues in your analytics! To make this more obvious, the player now reports a StuckPlayerException when it detects a stuck state. * Wakelock by default – The wake lock management was previously opt-in, resulting in hard to find edge cases where playback progress can be delayed a lot when running in the background. Now this feature is opt-out, so you don't have to worry about it and can also remove all manual wake lock handling around playback. * Simplified setting for CC button logic – Changing TrackSelectionParameters to say "turn subtitles on/off" was surprisingly hard to get right, so we added a simple boolean selectTextByDefault option for this use case. ### Simplify your media button preferences in MediaSession Until now, defining your preferences for which buttons should show up in the media notification drawer on Android Auto or WearOS required defining custom commands and buttons, even if you simply wanted to trigger a standard player method. Media3 1.9.0 has new functionality to make this a lot simpler – you can now define your media button preferences with a standard player command, requiring no custom command handling at all. session.setMediaButtonPreferences(listOf( CommandButton.Builder(CommandButton.ICON_FAST_FORWARD) // choose an icon .setDisplayName(R.string.skip_forward) .setPlayerCommand(Player.COMMAND_SEEK_FORWARD) // choose an action .build() )) Media button preferences with fast forward button ### CompositionPlayer for real-time preview The 1.9.0 release introduces CompositionPlayer under a new @ExperimentalApi annotation. The annotation indicates that it is available for experimentation, but is still under development. CompositionPlayer is a new component in the Media3 editing APIs designed for real-time preview of media edits. Built upon the familiar Media3 Player interface, CompositionPlayer allows users to see their changes in action before committing to the export process. It uses the same Composition object that you would pass to Transformer for exporting, streamlining the editing workflow by unifying the data model for preview and export. We encourage you to start using CompositionPlayer and share your feedback, and keep an eye out for forthcoming posts and updates to the documentation for more details. ### InAppMuxer as a default muxer in Transformer Transformer now uses InAppMp4Muxer as the default muxer for writing media container files. Internally, InAppMp4Muxer depends on the Media3 Muxer module, providing consistent behaviour across all API versions. Note that while Transformer no longer uses the Android platform's MediaMuxer by default, you can still provide FrameworkMuxer.Factory via setMuxerFactory if your use case requires it. ## ### New speed adjustment APIs The 1.9.0 release simplifies speed adjustments APIs for media editing. We've introduced new methods directly on EditedMediaItem.Builder to control speed, making the API more intuitive. You can now change the speed of a clip by calling setSpeed(SpeedProvider provider) on the EditedMediaItem.Builder: val speedProvider = object : SpeedProvider { override fun getSpeed(presentationTimeUs: Long): Float { return speed } override fun getNextSpeedChangeTimeUs(timeUs: Long): Long { return C.TIME_UNSET } } EditedMediaItem speedEffectItem = EditedMediaItem.Builder(mediaItem) .setSpeed(speedProvider) .build() This new approach replaces the previous method of using Effects#createExperimentalSpeedChangingEffects(), which we've deprecated and will remove in a future release. ### Introducing track types for EditedMediaItemSequence In the 1.9.0 release, EditedMediaItemSequence requires specifying desired output track types during sequence creation. This change ensures track handling is more explicit and robust across the entire Composition. This is done via a new EditedMediaItemSequence.Builder constructor that accepts a set of track types (e.g., C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO). To simplify creation, we've added new static convenience methods: * EditedMediaItemSequence.withAudioFrom(List<EditedMediaItem>) * EditedMediaItemSequence.withVideoFrom(List<EditedMediaItem>) * EditedMediaItemSequence.withAudioAndVideoFrom(List<EditedMediaItem>) We encourage you to migrate to the new constructor or the convenience methods for clearer and more reliable sequence definitions. Example of creating a video-only sequence: EditedMediaItemSequence videoOnlySequence = EditedMediaItemSequence.Builder(setOf(C.TRACK_TYPE_VIDEO)) .addItem(editedMediaItem) .build() --- Please get in touch via the Media3 issue Tracker if you run into any bugs, or if you have questions or feature requests. We look forward to hearing from you!
19.12.2025 22:00 👍 1 🔁 0 💬 0 📌 0
Preview
Goodbye Mobile Only, Hello Adaptive: Three essential updates from 2025 for building adaptive apps _Posted by Fahd Imtiaz – Product Manager, Android Developer_ _ _ _ _ ### Goodbye Mobile Only, Hello Adaptive: Three essential updates from 2025 for building adaptive apps In 2025 the Android ecosystem has grown far beyond the phone. Today, developers have the opportunity to reach over 500 million active devices, including foldables, tablets, XR, Chromebooks, and compatible cars. These aren't just additional screens; they represent a higher-value audience. We’ve seen that users who own both a phone and a tablet spend 9x more on apps and in-app purchases than those with just a phone. For foldable users, that average spend jumps to roughly 14x more*. This engagement signals a necessary shift in development: goodbye mobile apps, hello adaptive apps. To help you build for that future, we spent this year releasing tools that make adaptive the default way to build. Here are three key updates from 2025 designed to help you build these experiences. ### Standardizing adaptive behavior with Android 16 To support this shift, Android 16 introduced significant changes to how apps can restrict orientation and resizability. On displays of at least 600dp, manifest and runtime restrictions are ignored, meaning apps can no longer lock themselves to a specific orientation or size. Instead, they fill the entire display window, ensuring your UI scales seamlessly across portrait and landscape modes. Because this means your app context will change more frequently, it’s important to verify that you are preserving UI state during configuration changes. While Android 16 offers a temporary opt-out to help you manage this transition, Android 17 (SDK37) will make this behavior mandatory. To ensure your app behaves as expected under these new conditions, use the resizable emulator in Android Studio to test your adaptive layouts today. ### Supporting screens beyond the tablet with Jetpack WindowManager 1.5.0 As devices evolve, our existing definitions of "large" need to evolve with them. In October, we released Jetpack WindowManager 1.5.0 to better support the growing number of very large screens and desktop environments. On these surfaces, the standard "Expanded" layout, which usually fits two panes comfortably, often isn't enough. On a 27-inch monitor, two panes can look stretched and sparse, leaving valuable screen real estate unused. To solve this, WindowManager 1.5.0 introduced two new width window size classes: Large (1200dp to 1600dp) and Extra-large (1600dp+). These new breakpoints signal when to switch to high-density interfaces. Instead of stretching a typical list-detail view, you can take advantage of the width to show three or even four panes simultaneously.  Imagine an email client that comfortably displays your folders, the inbox list, the open message, and a calendar sidebar, all in a single view. Support for these window size classes was added to Compose Material 3 adaptive in the 1.2 release. ### Rethinking user journeys with Jetpack Navigation 3 Building a UI that morphs from a single phone screen to a multi-pane tablet layout used to require complex state management.  This often meant forcing a navigation graph designed for single destinations to handle simultaneous views. First announced at I/O 2025, Jetpack Navigation 3 is now stable, introducing a new approach to handling user journeys in adaptive apps. Built for Compose, Nav3 moves away from the monolithic graph structure. Instead, it provides decoupled building blocks that give you full control over your back stack and state. This solves the single source of truth challenge common in split-pane layouts. Because Nav3 uses the Scenes API, you can display multiple panes simultaneously without managing conflicting back stacks, simplifying the transition between compact and expanded views. ### A foundation for an adaptive future This year delivered the tools you need, from optimizing for expansive  layouts to the granular controls of WindowManager and Navigation 3. And, Android 16 began the shift toward truly flexible UI, with updates coming next year to deliver excellent adaptive experiences across all form factors. To learn more about adaptive development principles and get started, head over to d.android.com/adaptive-apps. The tools are ready, and the users are waiting. We can’t wait to see what you build! *Source: internal Google data
19.12.2025 17:00 👍 1 🔁 1 💬 0 📌 0
Preview
Bringing Androidify to Wear OS with Watch Face Push _Posted by Garan Jenkin - Developer Relations Engineer_ _ _ A few months ago we relaunched Androidify as an app for generating personalized Android bots. Androidify transforms your selfie photo into a playful Android bot using Gemini and Imagen. However, given that Android spans multiple form factors, including our most recent addition, XR, we thought, how could we bring the fun of Androidify to Wear OS? An Androidify watch face As Androidify bots are highly-personalized, the natural place to showcase them is the watch face. Not only is it the most frequently visible surface but also the most personal surface, allowing you to represent who you are. Personalized Androidify watch face, generated from selfie image Androidify now has the ability to generate a watch face dynamically within the phone app and then send it to your watch, where it will automatically be set as your watch face. All of this happens within seconds! High-level design End-to-end flow for watch face creation and installation In order to achieve the end-to-end experience, a number of technologies need to be combined together, as shown in this high-level design diagram. First of all, the user’s avatar is combined with a pre-existing Watch Face Format template, which is then packaged into an APK. This is validated - for reasons which will be explained! - and sent to the watch. On being received by the watch, the new Watch Face Push API - part of Wear OS 6- is used to install and activate the watch face. Let’s explore the details: ### Creating the watch face templates The watch face is created from a template, itself designed in Watch Face Designer. This is our new Figma plugin that allows you to create Watch Face Format watch faces directly within Figma. An Androidify watch face template in Watch Face Designer ** ** The plugin allows the watch face to be exported in a range of different ways, including as Watch Face Format (WFF) resources. These can then be easily incorporated as assets within the Androidify app, for dynamically building the finalized watch face. ### Packaging and validation Once the template and avatar have been combined, the Portable Asset Compiler Kit (Pack) is used to assemble an APK. In Androidify, Pack is used as a native library on the phone. For more details on how Androidify interfaces with the Pack library, see the GitHub repository. As a final step before transmission, the APK is checked by the Watch Face Push validator. This validator checks that the APK is suitable for installation. This includes checking the contents of the APK to ensure it is a valid watch face, as well as some performance checks. If it is valid, then the validator produces a token. This token is required by the watch for installation. ### Sending the watch face The Androidify app on Wear OS uses WearableListenerService to listen for events on the Wearable Data Layer. The phone app transfers the watch face by using a combination of MessageClient to set up the process, then ChannelClient to stream the APK. ### Installing the watch face on the watch Once the watch face is received on the Wear OS device, the Androidify app uses the new Watch Face Push API to install the watch face: val wfpManager =     WatchFacePushManagerFactory.createWatchFacePushManager(context) val response = wfpManager.listWatchFaces() ** ** try {     if (response.remainingSlotCount > 0) {         wfpManager.addWatchFace(apkFd, token)     } else {         val slotId = response.installedWatchFaceDetails.first().slotId         wfpManager.updateWatchFace(slotId, apkFd, token)     } } catch (a: WatchFacePushManager.AddWatchFaceException) {     return WatchFaceInstallError.WATCH_FACE_INSTALL_ERROR } catch (u: WatchFacePushManager.UpdateWatchFaceException) {     return WatchFaceInstallError.WATCH_FACE_INSTALL_ERROR } Androidify uses either the addWatchFace or updateWatchFace method, depending on the scenario: Watch Face Push defines a concept of “slots” - how many watch faces a given app can have installed at any time. For Wear OS 6, this value is in fact 1. Androidify’s approach is to install the watch face if there is a free slot, and if not, any existing watch face is swapped out for the new one. ### Setting the active watch face Installing the watch face programmatically is a great step, but Androidify seeks to ensure the watch face is also the active watch face. Watch Face Push introduces a new runtime permission which must be granted in order for apps to be able to achieve this: com.google.wear.permission.SET_PUSHED_WATCH_FACE_AS_ACTIVE Once this permission has been acquired, the wfpManager.setWatchFaceAsActive() method can be called, to set an installed watch face to being the active watch face. However, there are a number of considerations that Androidify has to navigate: * setWatchFaceAsActive can only be used once. * SET_PUSHED_WATCH_FACE_AS_ACTIVE cannot be re-requested after being denied by the user. * Androidify might already be in control of the active watch face. For more details see how Androidify implements the set active logic. ### Get started with Watch Face Push for Wear OS Watch Face Push is a versatile API, equally suited to enhancing Androidify as it is to building fully-featured watch face marketplaces. Perhaps you have an existing phone app and are looking for opportunities to further engage and delight your users? Or perhaps you’re an existing watch face developer looking to create your own community and gallery through releasing a marketplace app? Take a look at these resources: * Watch Face Push * Watch Face Format - Note also the upcoming policy changes relating to watch face publishing. * Watch Face Designer * Androidify GitHub repository * Androidify Play Store listing And also check out the accompanying video for a greater-depth look at how we brought Androidify to Wear OS! We’re looking forward to what you’ll create with Watch Face Push!
18.12.2025 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
Brighten Your Real-Time Camera Feeds with Low Light Boost _Posted by Donovan McMurray, Developer Relations Engineer_ We recently shared how Instagram enabled users to take stunning low light photos using Night Mode. That feature is perfect for still images, where there’s time to combine multiple exposures to create a high-quality static shot. But what about the moments that happen between the photos? Users need to interact with the camera more than just the moment the shutter button is pressed. They also use the preview to compose their scene or scan QR codes. Today, we’re diving into Low Light Boost (LLB), a powerful feature designed to brighten real-time camera streams. Unlike Night Mode, which requires a hold-still capture duration, Low Light Boost works instantaneously on your live preview and video recordings. LLB automatically adjusts how much brightening is needed based on available light, so it’s optimized for every environment. With a recent update, LLB allows Instagram users to line up the perfect shot, and then their existing Night Mode implementation results in the same high quality low-light photos their users have been enjoying for over a year. ## Why Real-time Brightness Matters While Night Mode aims to improve final image quality, Low Light Boost is intended for usability and interactivity in dark environments. Another important factor to consider is that – even though they work together very well – you can use LLB and Night Mode independently, and you’ll see with some of these use cases, LLB has value on its own when Night Mode photos aren’t needed. Here is how LLB improves the user experience: * Better Framing & Capture: In dimly lit scenes, a standard camera preview can be pitch black. LLB brightens the viewfinder, allowing users to actually see what they are framing before they hit the shutter button. For this experience, you can use Night Mode for the best quality low-light photo result, or you can let LLB give the user a “what you see is what you get” photo result. * Reliable Scanning: QR codes are ubiquitous, but scanning them in a dark restaurant or parking garage is often frustrating. With a significantly brighter camera feed, scanning algorithms can reliably detect and decode QR codes even in very dim environments. * Enhanced Interactions: For apps involving live video interactions (like AI assistants or video calls) LLB increases the amount of perceivable information, ensuring the computer vision models have enough data to work with ## The Difference in Instagram The engineering team behind the Android Instagram app is always hard at work to provide a state-of-the-art camera experience for their users. You can see in the above example just what a difference LLB makes on a Pixel 10 Pro. It’s easy to imagine the difference this makes in the user experience. If users aren’t able to see what they’re capturing, then there’s a higher chance they’ll abandon the capture. ## Choosing Your Implementation There are two ways to implement Low Light Boost to provide the best experience across the widest range of devices: 1. Low Light Boost AE Mode: This is a hardware-layer auto-exposure mode. It offers the highest quality and performance because it fine-tunes the Image Signal Processor (ISP) pipeline directly. Always check for this first. 2. Google Low Light Boost: If the device doesn't support the AE mode, you can fall back to this software-based solution provided by Google Play services. It applies post-processing to the camera stream to brighten it. As an all-software solution, it is available on more devices, so this implementation helps you reach more devices with LLB. ### Low Light Boost AE Mode (Hardware) Mechanism: This mode is supported on devices running Android 15 and newer and requires the OEM to have implemented the support in HAL (currently available on Pixel 10 devices). It integrates directly with the camera's Image Signal Processor (ISP). If you set CaptureRequest.CONTROL_AE_MODE to CameraMetadata.CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY, the camera system takes control. Behavior: The HAL/ISP analyzes the scene and adjusts sensor and processing parameters, often including increasing exposure time, to brighten the image. This can yield frames with a significantly improved signal-to-noise ratio (SNR) because the extended exposure time, rather than an increase in digital sensor gain (ISO), allows the sensor to capture more light information. Advantage: Potentially better image quality and power efficiency as it leverages dedicated hardware pathways. Trade off: May result in a lower frame rate in very dark conditions as the sensor needs more time to capture light. The frame rate can drop to as low as 10 FPS in very low light conditions. ### Google Low Light Boost (Software via Google Play Services) Mechanism: This solution, distributed as an optional module via Google Play services, applies post-processing to the camera stream. It uses a sophisticated realtime image enhancement technology called HDRNet. Google HDRNet: This deep learning model analyzes the image at a lower resolution to predict a compact set of parameters (a bilateral grid). This grid then guides the efficient, spatially-varying enhancement of the full-resolution image on the GPU. The model is trained to brighten and improve image quality in low-light conditions, with a focus on face visibility. Process Orchestration: The HDRNet model and its accompanying logic are orchestrated by the Low Light Boost processor. This includes: 1. Scene Analysis: A custom calculator that estimates the true scene brightness using camera metadata (sensor sensitivity, exposure time, etc.) and image content. This analysis determines the boost level. 2. HDRNet Processing: Applies the HDRNet model to brighten the frame. The model used is tuned for low light scenes and optimized for realtime performance. 3. Blending: The original and HDRNet processed frames are blended. The amount of blending applied is dynamically controlled by the scene brightness calculator, ensuring a smooth transition between boosted and unboosted states. Advantage: Works on a broader range of devices (currently supports Samsung S22 Ultra, S23 Ultra, S24 Ultra, S25 Ultra, and Pixel 6 through Pixel 9) without requiring specific HAL support. Maintains the camera's frame rate as it's a post-processing effect. Trade-off: As a post-processing method, the quality is limited by the information present in the frames delivered by the sensor. It cannot recover details lost due to extreme darkness at the sensor level. By offering both hardware and software pathways, Low Light Boost provides a scalable solution to enhance low-light camera performance across the Android ecosystem. Developers should prioritize the AE mode where available and use the Google Low Light Boost as a robust fallback. ## Implementing Low Light Boost in Your App Now let’s look at how to implement both LLB offerings. You can implement the following whether you use CameraX or Camera2 in your app. For the best results, we recommend implementing both Step 1 and Step 2. ### Step 1: Low Light Boost AE Mode Available on select devices running Android 15 and higher, LLB AE Mode functions as a specific Auto-Exposure (AE) mode. #### 1. Check for Availability First, check if the camera device supports LLB AE Mode. val cameraInfo = cameraProvider.getCameraInfo(cameraSelector) val isLlbSupported = cameraInfo.isLowLightBoostSupported #### 2. Enable the Mode If supported, you can enable LLB AE Mode using CameraX’s CameraControl object. // After setting up your camera, use the CameraInfo object to enable LLB AE Mode. camera = cameraProvider.bindToLifecycle(...) if (isLlbSupported) { try { // The .await() extension suspends the coroutine until the // ListenableFuture completes. If the operation fails, it throws // an exception which we catch below. camera?.cameraControl.enableLowLightBoostAsync(true).await() } catch (e: IllegalStateException) { Log.e(TAG, "Failed to enable low light boost: not available on this device or with the current camera configuration", e) } catch (e: CameraControl.OperationCanceledException) { Log.e(TAG, "Failed to enable low light boost: camera is closed or value has changed", e) } } #### 3. Monitor the State Just because you requested the mode doesn't mean it's currently "boosting." The system only activates the boost when the scene is actually dark. You can set up an Observer to update your UI (like showing a moon icon) or convert to a Flow using the extension function asFlow(). if (isLlbSupported) { camera?.cameraInfo.lowLightBoostState.asFlow().collectLatest { state -> // Update UI accordingly updateMoonIcon(state == LowLightBoostState.ACTIVE) } } You can read the full guide on Low Light Boost AE Mode here. ### Step 2: Google Low Light Boost For devices that don't support the hardware AE mode, Google Low Light Boost acts as a powerful fallback. It uses a LowLightBoostSession to intercept and brighten the stream. #### 1. Add Dependencies This feature is delivered via Google Play services. implementation("com.google.android.gms:play-services-camera-low-light-boost:16.0.1-beta06") // Add coroutines-play-services to simplify Task APIs implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.2") #### 2. Initialize the Client Before starting your camera, use the LowLightBoostClient to ensure the module is installed and the device is supported. val llbClient = LowLightBoost.getClient(context) // Check support and install if necessary val isSupported = llbClient.isCameraSupported(cameraId).await() val isInstalled = llbClient.isModuleInstalled().await() if (isSupported && !isInstalled) { // Trigger installation llbClient.installModule(installCallback).await() } #### 3. Create a LLB Session Google LLB processes each frame, so you must give your display Surface to the LowLightBoostSession, and it gives you back a Surface that has the brightening applied. For Camera2 apps, you can add the resulting Surface with CaptureRequest.Builder.addTarget(). For CameraX, this processing pipeline aligns best with the CameraEffect class, where you can apply the effect with a SurfaceProcessor and provide it back to your Preview with a SurfaceProvider, as seen in this code. // With a SurfaceOutput from SurfaceProcessor.onSurfaceOutput() and a // SurfaceRequest from Preview.SurfaceProvider.onSurfaceRequested(), // create a LLB Session. suspend fun createLlbSession(surfaceRequest: SurfaceRequest, outputSurfaceForLlb: Surface) { // 1. Create the LLB Session configuration val options = LowLightBoostOptions( outputSurfaceForLlb, cameraId, surfaceRequest.resolution.width, surfaceRequest.resolution.height, true // Start enabled ) // 2. Create the session. val llbSession = llbClient.createSession(options, callback).await() // 3. Get the surface to use. val llbInputSurface = llbSession.getCameraSurface() // 4. Provide the surface to the CameraX Preview UseCase. surfaceRequest.provideSurface(llbInputSurface, executor, resultListener) // 5. Set the scene detector callback to monitor how much boost is being applied. val onSceneBrightnessChanged = object : SceneDetectorCallback { override fun onSceneBrightnessChanged( session: LowLightBoostSession, boostStrength: Float ) { // Monitor the boostStrength from 0 (no boosting) to 1 (maximum boosting) } } llbSession.setSceneDetectorCallback(onSceneBrightnessChanged, null) } #### 4. Pass in the Metadata For the algorithm to work, it needs to analyze the camera's auto-exposure state. You must pass capture results back to the LLB session. In CameraX, this can be done by extending your Preview.Builder with Camera2Interop.Extender.setSessionCaptureCallback(). Camera2Interop.Extender(previewBuilder).setSessionCaptureCallback( object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted( session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult ) { super.onCaptureCompleted(session, request, result) llbSession?.processCaptureResult(result) } } ) Detailed implementation steps for the client and session can be found in the Google Low Light Boost guide. ## Next Steps By implementing these two options, you ensure that your users can see clearly, scan reliably, and interact effectively, regardless of the lighting conditions. To see these features in action within a complete, production-ready codebase, check out the Jetpack Camera App on GitHub. It implements both LLB AE Mode and Google LLB, giving you a reference for your own integration.
17.12.2025 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
Build smarter apps with Gemini 3 Flash _Posted by Thomas Ezan, Senior Developer Relations Engineer_ _ _ _ _ Today, we're expanding the Gemini 3 model family with the release of Gemini 3 Flash, frontier intelligence built for speed at a fraction of the cost. You can start building with it immediately, as we’re officially launching Gemini 3 Flash on Firebase AI Logic. Available globally, you can securely access the Gemini 3 Flash preview model directly from your app via the Gemini Developer API or the Vertex AI Gemini API using Firebase AI Logic client SDKs. Gemini 3 Flash’s strong performance in reasoning, tool use, and multimodal capabilities is ideal for developers looking to do more complex video analysis, data extraction and visual Q&A. ### Gemini 3 optimized for low-latency Gemini 3 is our most intelligent model family to date. With the launch of Gemini 3 Flash, we are making that intelligence more accessible for low-latency and cost-effective use cases. While Gemini 3 Pro is designed for complex reasoning, Gemini 3 Flash is engineered to be significantly faster and more cost-effective for your production apps. ### Seamless integration with Firebase AI Logic Just like the Pro model, Gemini 3 Flash is available in preview directly through the Firebase AI Logic SDK. This means you can integrate it into your Android app without needing to do any complex server side setup. Here is how to add it to your Kotlin code: val model = Firebase.ai(backend = GenerativeBackend.googleAI()) .generativeModel( modelName = "gemini-3-flash-preview") ### Scale with Confidence In addition, Firebase enables you to keep your growth secure and manageable with: ### AI Monitoring The Firebase AI monitoring dashboard gives you visibility into latency, success rates, and costs, allowing you to slice data by model name to see exactly how the model performs. ### Server Prompt Templates You can use server prompt templates to store your prompt and schema securely on Firebase servers instead of hardcoding them in your app binary. This capability ensures your sensitive prompts remain secure, prevents unauthorized prompt extraction, and allows for faster iteration without requiring app updates. --- model: 'gemini-3-flash-preview' input: schema: topic: type: 'string' minLength: 2 maxLength: 40 length: type: 'number' minimum: 1 maximum: 200 language: type: 'string' --- {{role "system"}} You're a storyteller that tells nice and joyful stories with happy endings. {{role "user"}} Create a story about {{topic}} with the length of {{length}} words in the {{language}} language. Prompt template defined on the Firebase Console val generativeModel = Firebase.ai.templateGenerativeModel() val response = generativeModel.generateContent("storyteller-v10", mapOf( "topic" to topic, "length" to length, "language" to language ) ) _output.value = response.text Code snippet to access to the prompt template ### Gemini 3 Flash for AI development assistance in Android Studio Gemini 3 Flash is also available for AI assistance in Android Studio. While Gemini 3 Pro Preview is our best model for coding and agentic experiences, Gemini 3 Flash is engineered for speed, and great for common development tasks and questions. The new model is rolling out to developers using Gemini in Android Studio at no-cost (default model) starting today. For higher usage rate limits and longer sessions with Agent Mode, you can use an AI Studio API key to leverage the full capabilities of either Gemini 3 Flash or Gemini 3 Pro. We’re also rolling out Gemini 3 model family access with higher usage rate limits to developers who have Gemini Code Assist Standard or Enterprise licenses. Your IT administrator will need to enable access to preview models through the Google Cloud console. ### Get Started Today You can start experimenting with Gemini 3 Flash via Firebase AI Logic today. Learn more about it in the Android and Firebase documentation. Try out any of the new Gemini 3 models in Android Studio for development assistance, and let us know what you think! As always you can follow us across LinkedIn, Blog, YouTube, and X.
17.12.2025 16:13 👍 0 🔁 0 💬 0 📌 0
Preview
Notes from Google Play: A look back at the tools that powered your growth in 2025 _Posted by Sam Bright – VP & GM, Google Play + Developer Ecosystem_ _ _ Hi everyone, Thank you for making 2025 another amazing year for Google Play. Together, we’ve built Play into something much more than a store—it’s a dynamic ecosystem powered by your creativity. This year, our focus was ensuring Play continues to be the best destination for people to discover incredible content and enjoy rewarding gaming experiences. We're incredibly proud of the progress we've made alongside you, and we’re excited to celebrate those who pushed the boundaries of what’s possible—like the winners of our Best of 2025 awards. Watch our recap video to see how we’ve made Play even more rewarding for your business, or read on for a more in-depth look back on the year. ### Evolving Play to be more than a store This year, we focused on evolving Play into a true destination for discovery where billions of people around the world can find and enjoy experiences that make life more productive and delightful. Making Play the best destination for your games business Just a few months ago, we shared our vision for a more unified experience that brings more fun to gaming. Today, players often jump between different platforms to discover, play, and get rewarded. Our goal is to connect these journeys to create the best experience for players and, consequently, grow your business. Our first steps include these key updates: * A new Gamer Profile that tracks cross-game stats, streaks, and achievements, customizable with a Gen AI Avatar. * Integrated Rewards across mobile and PC that give players access to VIP experiences like our Four Days of Fantastic Rewards at San Diego Comic-Con,  Diamond District experience on Roblox, and Play’s own treasure-hunt mini-game Diamond Valley alongside new Play Games Leagues where players can compete in their favorite games, climb leaderboards, and win Play Points rewards. * The new Play Games Sidekick, a helpful in-game overlay that curates and organizes relevant gaming info, and provides direct access to Gemini Live for real-time AI-powered guidance in the game. We recently rolled out the open beta to developers, and we encourage you to start testing the sidekick in your games and share your feedback. * Integrated gameplay across devices is now fully realized as Google Play Games on PC has graduated from beta to general availability, solidifying our commitment to cross-platform play and making our catalog of over 200,000 titles available across mobile and PC. Play Games Sidekick is a new in-game overlay that gives players instant access to their rewards, offers, and achievements, driving higher engagement for your game. To help you get the most out of this unified gaming experience, we introduced the Google Play Games Level Up program, a new way to unlock greater success for your business. For titles that meet core user experience guidelines, you can unlock a powerful suite of benefits including the ability to: * Re-engage players on the new You tab, a new personalized destination on the Play Store that is designed to help you re-engage and retain players by showcasing content and rewards from recently played games in one dedicated space. You can utilize engagement tools in Play Console to feature your latest events, offers, and updates. * Maximize your game’s reach with prominent boosts across the store, including featuring opportunities, Play Points boosters and quests, and enhanced visibility on editorial surfaces like the Games Home and Play Points Home. You tab is a personalized destination designed to help you re-engage and retain players by showcasing your latest events, offers, and updates. Unlocking more discovery and engagement for your apps and its content Last year, we shared our vision for a content-rich Google Play that has already delivered strong results. Year-over-year, Apps Home has seen over an 18% increase in average monthly visitors with apps seeing a 9% growth in acquisitions and double-digit growth* in app spend for those monetizing on Google Play. We introduced even more updates to elevate discovery and engagement on and off the store. * Curated spaces, launched last year, have been a success, fostering routine engagement by delivering daily, locally relevant content (such as football highlights in Brazil, cricket in India, and comics in Japan) directly to the Apps Home. Building on this, we expanded to new categories and locations, including a new entertainment-focused space in Korea. Curated spaces make it easier to find and engage with local interests. * We significantly increased timely, relevant content on Google Play through Spotlight and new topic browse pages. Spotlight, located at the top of Apps Home, offers seasonal content feeds—like Taylor Swift’s recent album launch or holiday movie guides—in a new, immersive way to connect users with current cultural moments. Concurrently, new topic browse pages were integrated across the store in the U.S., Japan, and South Korea, allowing content deep dives into over 100,000 shows and movies. Spotlight offers an immersive experience connecting users with relevant apps during current cultural moments. Last year, we introduced Engage SDK to help you deliver personalized content to users across surfaces and seamlessly guide them into the relevant in-app experiences. Integrating it unlocks surfaces like Collections, our immersive full-screen experience bringing content directly to the user's home screen. This year, we rolled out updates to expand your content’s reach even further: * Engage SDK content expanded to the Play Store this summer, enabling seamless re-engagement across Apps Home and the new You tab. * Rolled out to more markets, including Brazil, Germany, India, Japan, and Korea. ### Supporting you throughout your app lifecycle In addition to evolving the store, we’ve continued to build on our powerful toolset to support you at every stage, from testing and release to growth and monetization. Helping you deliver high-quality, trusted user experiences We launched key updates in Android Studio and Play Console to help you build more stable and compliant apps. * Policy insights in Android Studio help you catch potential violations early by showing in-context guidance, such as policy summaries and best practices, whenever code related to a Google Play policy is detected. * You can now halt fully rolled-out releases to stop the distribution of problematic app versions through Play Console and the Publishing API. * We also added new Android vitals performance metrics, including low memory kill metrics which provides device-specific insights to resolve stability problems and excessive partial wake lock metrics to help you address battery drain. New _Android vitals metrics h_ elp you resolve stability problems and address battery drain. Boosting your productivity and workflow We refined the Play Console experience to make managing your app and your marketing content more efficient. * We put your most essential insights front and center with a redesigned app dashboard and overview pages. * To repurpose creative content across Play Console more easily, we launched an asset library that lets you upload from Google Drive, organize with tags, and crop existing visuals. * You can now automatically translate app strings with Gemini at no cost. This feature eliminates manual translation work for new releases, making updates seamless. You remain in full control with the ability to preview translations using a built-in emulator, and can easily edit or disable the service. Translate app strings automatically with Gemini, while maintaining full control for previewing and editing. Maximizing your revenue with secure, frictionless payments We introduced new features focused on driving purchases and maximizing subscription revenue globally. * We’re improving purchase conversion globally with over 800 million users now ready to buy. We launched features that encourage users to set up payment methods early, provide AI-powered payment method recommendations, and expanded our payment library to support more local payment methods globally. * To maximize recurring revenue from over 400 million paid subscriptions, we introduced multi-product checkout, allowing you to sell base subscriptions and add-ons under a simple, single transaction. * To combat churn, we began showcasing subscription benefits in more places and provided you with more flexible options like extended grace periods and account holds for declined payments, which has proven effective in reducing involuntary churn by an average of 10%*. To help reduce voluntary churn, we’re showcasing your subscriptions benefits across Play. ### Investing in our app and game community with developer programs We’re proud to invest in programs for app and game companies around the world to help you grow and succeed on Play. * Google Play Apps Accelerator: We’ve opened submissions for our program that will help early-stage app companies scale their business. Selected companies from over 80 eligible countries will join a 12-week accelerator starting in March 2026, where they can learn more about creating high-quality apps, go-to-market strategies, user acquisition, and more. Submissions are still open for our 12-week accelerator, which starts in March 2026. Apply by January 7, 2026 for consideration. * Indie Games Fund (Latin America): Now in its fourth year, this fund provides support to 10 promising game studios in Latin America with funding and hands-on support from Google Play. In October, we announced the 2025 recipients. * ChangGoo Program (South Korea): Now in its seventh year, this program works with over 100 Korean mobile app and game startups to foster their growth and expansion in collaboration with the Ministry of SMEs and Startups and the Korean Institute of Startup and Entrepreneurship Development (KISED). * Google Play x Unity Game Developer Training Program (Indonesia): The third edition launched in April, offering a 6-month online curriculum, meetups, and mentorship for Indonesian game developers in partnership with Indonesia’s Ministry of Creative Economy and the Indonesian Gaming Association. * Google Play x Unity Game Developer Training Program (India): The first India cohort kicked off in November with 500 aspiring and professional game developers. The 6-month journey provides online curriculum and meetups in partnership with GDAI and the govt of Tamil Nadu and Maharashtra. * Google for Startups Accelerator program (India): We provided Seed to Series-A AI-powered app startups in India with insights on the latest AI advancements, mentorship, and expert guidance. ### ### Protecting your business and our ecosystem At the heart of all the progress we’ve made this year is a foundation of trust and security. We're always innovating to make Play safer for everyone—so users can trust every app they download and so you can keep building a thriving business. To offer stronger protection for your business and users, we continued to enhance the Play Integrity API and our anti-fraud systems. On average, apps using Play Integrity features see 80% lower unauthorized usage, and our efforts have safeguarded top apps using Play Billing from $2.9 billion in fraud and abuse in the last year. * Automatically fix user issues: New Play in-app remediation prompts in Play Integrity API automatically guide users to fix common problems like network issues, outdated Google Play Services, or device integrity flags, reducing integration complexity and getting users back to a good state faster. * Combat repeat bad actors: Device recall is a powerful new tool that lets you store and recall limited data associated with a device, even if the device is reset, helping protect your business model from repeat bad actors. * Strengthen revenue protection: We've introduced stronger protections against abuse, including refining pricing arbitrage detection and enhancing protection against free trial and intro pricing abuse for subscriptions, helping your business models remain profitable. With in-app remediation prompts, Play automatically handles a wide range of issues to guide your users back to a good state. For a full breakdown of new ways we’re keeping the ecosystem safe, check out our deep-dive blog post here. ### Thank you for your partnership This is an incredible time for Google Play. We’ve made huge strides together – your passion, creativity, and feedback throughout 2025 has made Play that much stronger. We’re grateful to work alongside the best developer community in the world, and we look forward to unlocking even greater success together in the new year. Happy holidays! Sam Bright VP & GM, Google Play + Developer Ecosystem * Source: Internal Google data
15.12.2025 17:00 👍 0 🔁 0 💬 0 📌 0
Preview
18% Faster Compiles, 0% Compromises _Posted by Santiago Aboy Solanes - Software Engineer, Vladimír Marko - Software Engineer_ The Android Runtime (ART) team has reduced compile time by 18% without compromising the compiled code or any peak memory regressions. This improvement was part of our 2025 initiative to improve compile time without sacrificing memory usage or the quality of the compiled code. Optimizing compile-time speed is crucial for ART. For example, when just-in-time (JIT) compiling it directly impacts the efficiency of applications and overall device performance. Faster compilations reduce the time before the optimizations kick in, leading to a smoother and more responsive user experience. Furthermore, for both JIT and ahead-of-time (AOT), improvements in compile-time speed translate to reduced resource consumption during the compilation process, benefiting battery life and device thermals, especially on lower-end devices. Some of these compile-time speed improvements launched in the June 2025 Android release, and the rest will be available in the end-of-year release of Android. Furthermore, all Android users on versions 12 and above are eligible to receive these improvements through mainline updates. # Optimizing the optimizing compiler Optimizing a compiler is always a game of trade-offs. You can't just get speed for free; you have to give something up. We set a very clear and challenging goal for ourselves: make the compiler faster, but do it without introducing memory regressions and, crucially, without degrading the quality of the code it produces. If the compiler is faster but the apps run slower, we've failed. The one resource we were willing to spend was our own development time to dig deep, investigate, and find clever solutions that met these strict criteria. Let’s take a closer look at how we work to find areas to improve, as well as finding the right solutions to the various problems. Finding worthwhile possible optimizations Before you can begin to optimize a metric, you have to be able to measure it. Otherwise, you can’t ever be sure if you improved it or not. Luckily for us, compile time speed is fairly consistent as long as you take some precautions like using the same device you use for measuring before and after a change, and making sure you don’t thermal throttle your device. On top of that, we also have deterministic measurements like compiler statistics that help us understand what’s going on under the hood. Since the resource we were sacrificing for these improvements was our development time, we wanted to be able to iterate as fast as we could. This meant that we grabbed a handful of representative apps (a mix of first-party apps, third-party apps, and the Android operating system itself) to prototype solutions. Later, we verified that the final implementation was worth it with both manual and automated testing in a widespread manner. With that set of hand-picked apks we would trigger a manual compile locally, get a profile of the compilation, and use pprof to visualize where we are spending our time. Example of a profile’s flame graph in pprof The pprof tool is very powerful and allows us to slice, filter, and sort the data to see, for example, which compiler phases or methods are taking most of the time. We will not go into detail about pprof itself; just know that if the bar is bigger then it means it took more time of the compilation. One of these views is the “bottom up” one where you can see which methods are taking most of the time. In the image below we can see a method called Kill, accounting for over a 1% of the compile time. Some of the other top methods will also be discussed later in the blog post. Bottom up view of a profile In our optimizing compiler, there’s a phase called Global Value Numbering (GVN). You don’t have to worry about what it does as a whole, but the relevant part is to know that it has a method called `Kill` that it will delete some nodes according to a filter. This is time consuming as it has to iterate through all the nodes and check one by one. We noticed that there are some cases in which we know in advance that the check will be false, no matter the nodes we have alive at that point. In these cases, we can skip iterating altogether, bringing it from 1.023% down to ~0.3% and improving GVN’s runtime by ~15%. ## Implementing worthwhile optimizations We covered how to measure and how to detect where the time is being spent, but this is only the beginning. The next step is how to optimize the time being spent compiling. Usually, in a case like the `Kill` one above we would take a look at how we iterate through the nodes and do it faster by, for example, doing things in parallel or improving the algorithm itself. In fact, that’s what we tried at first and only when we couldn’t find anything to do we had a “Wait a minute…” moment and saw that the solution was to (in some cases) not iterate at all! When doing these kinds of optimizations, it is easy to miss the forest for the trees. In other cases, we used a handful of different techniques including: * using heuristics to decide whether an optimization will fail to produce worthwhile results and therefore can be skipped * using extra data structures to cache computed data * changing the current data structures to get a speed boost * lazily computing results to avoid cycles in some cases * use the right abstraction - unnecessary features can slow down the code * avoid chasing a frequently used pointer through many loads ## How do we know if the optimizations are worth pursuing? That’s the neat part, you don’t. After detecting that an area is consuming a lot of compile time and after devoting development time to try to improve it, sometimes you can’t just find a solution. Maybe there’s nothing to do, it will take too long to implement, it will regress another metric significantly, increase code base complexity, etc. For every successful optimization that you can see in this blog post, know that there are countless others that just didn’t come to fruition. If you are in a similar situation, try to estimate how much you are going to improve the metric by doing as little work as you can. This means, in order: 1. Estimating with a metrics you have already collected, or just a gut feeling 2. Estimating with a quick and dirty prototype 3. Implement a solution. Don’t forget to consider estimating the drawbacks of your solution. For example, if you are going to rely on extra data structures, how much memory are you willing to use? # Diving deeper Without further ado, let’s look at some of the changes we implemented. We implemented a change to optimize a method called FindReferenceInfoOf. This method was doing a linear search of a vector to find an entry. We updated that data structure to be indexed by the instruction’s id so that FindReferenceInfoOf would be O(1) instead of O(n). Also, we pre-allocated the vector to avoid resizing. We slightly increased memory as we had to add an extra field which counted how many entries we inserted in the vector, but it was a small sacrifice to make as the peak memory didn’t increase. This sped up our LoadStoreAnalysis phase by 34-66% which in turns gives ~0.5-1.8% compile time improvement. We have a custom implementation of HashSet that we use in several places. Creating this data structure was taking a considerable amount of time and we found out why. Many years ago, this data structure was used in only a few places that were using very big HashSets and it was tweaked to be optimized for that. However, nowadays it was used in the opposite direction with only a few entries and with a short lifespan. This meant that we were wasting cycles by creating this huge HashSet but we only used it for a few entries before discarding it. With this change, compile time improved ~1.3-2% of compile time. As an added bonus, memory usage decreased by ~0.5-1% since we weren’t using as big data structures as before. We improved ~0.5-1% of compile time by passing data structures by reference to the lambda to avoid copying them around. This was something that was missed in the original review and sat in our codebase for years. It was thanks to taking a look at the profiles in pprof that we noticed that these methods were creating and destroying a lot of data structures, which led us to investigate and optimize them. We sped up the phase that writes the compiled output by caching computed values, which translated to ~1.3-2.8% of total compile time improvement. Sadly, the extra bookkeeping was too much and our automated testing alerted us of the memory regression. Later, we took a second look at the same code and implemented a new version which not only took care of the memory regression but also improved the compile time a further ~0.5-1.8%! In this second change we had to refactor and reimagine how this phase should work, in order to get rid of one of the two data structures. We have a phase in our optimizing compiler which inlines function calls in order to get better performance. To choose which methods to inline we use both heuristics before we do any computation, and final checks after doing work but right before we finalize the inlining. If any of those detect that the inlining is not worth it (for example, too many new instructions would be added), then we don’t inline the method call. We moved two checks from the “final checks” category to the “heuristic” category to estimate whether an inlining will succeed or not before we do any time-expensive computation. Since this is an estimate it is not perfect, but we verified that our new heuristics cover 99.9% of what was inlined before without affecting performance. One of these new heuristics was about the needed DEX registers (~0.2-1.3% improvement), and the other one about number of instructions (~2% improvement). We have a custom implementation of a BitVector that we use in several places. We replaced the resizable BitVector class with a simpler BitVectorView for certain fixed-size bit vectors. This eliminates some indirections and run-time range checks and speeds up the construction of the bit vector objects. Furthermore, the BitVectorView class was templatized on the underlying storage type (instead of always using uint32_t as the old BitVector). This allows some operations, for example Union(), to process twice as many bits together on 64-bit platforms. The samples of the affected functions were reduced by more than 1% in total when compiling the Android OS. This was done across several changes 1, 2, 3, 4, 5, [6] If we talked in detail about all the optimizations we would be here all day! If you are interested in some more optimizations, take a look at some other changes we implemented: * Add bookkeeping to improve compilation times by ~0.6-1.6%. * Lazily compute data to avoid cycles, if possible. * Refactor our code to skip precomputing work when it will not be used. * Avoid some dependent load chains when the allocator can be readily obtained from other places. * Another case of adding a check to avoid unnecessary work. * Avoid frequent branching on register type (core/FP) in register allocator. * Make sure some arrays are initialized at compile time. Don’t rely on clang to do it. * Clean up some loops. Use range loops that clang can optimize better because it does not need to reload the internal pointers of the container due to loop side effects. Avoid calling the virtual function `HInstruction::GetInputRecords()` in the loop via the inlined `InputAt(.)` for each input. * Avoid Accept() functions for the visitor pattern by exploiting a compiler optimization. # Conclusion Our dedication to improving ART’s compile-time speed has yielded significant improvements, making Android more fluid and efficient while also contributing to better battery life and device thermals. By diligently identifying and implementing optimizations, we've demonstrated that substantial compile-time gains are possible without compromising memory usage or code quality. Our journey involved profiling with tools like pprof, a willingness to iterate, and sometimes even abandon less fruitful avenues. The collective efforts of the ART team have not only reduced compile time by a noteworthy percentage, but have also laid the groundwork for future advancements. All of these improvements are available in the 2025 end-of-year Android update, and for Android 12 and above through mainline updates. We hope this deep dive into our optimization process provides valuable insights into the complexities and rewards of compiler engineering!
15.12.2025 17:00 👍 0 🔁 0 💬 0 📌 0