31 Aug 2026

feedTalkAndroid

How Did This K-Drama Become the World’s #1 Series Overnight?

How on earth did a low-key Korean drama rocket from relative obscurity to the absolute top of Netflix's…

31 Aug 2026 3:00pm GMT

The Best Meta Quest 3S Straps

A better strap turns the Quest 3S from a tolerable headset into a longer-lasting and comfortable hardware.

31 Aug 2026 10:02am GMT

Netflix Drops a Must-Watch Historical Mini-Series for Bridgerton Fans—Is This the New Summer Hit?

Looking for your next historical binge after finishing Bridgerton? Netflix's mini-series My Brilliant Career is here, and it's…

31 Aug 2026 6:00am GMT

30 Aug 2026

feedTalkAndroid

Android Auto vs Android Automotive: What’s the Real Difference for Drivers?

Ever noticed your car's touchscreen looks a lot like your smartphone, but isn't quite the same? If you're…

30 Aug 2026 3:00pm GMT

Aviator APK Download for Android

If you're new to Aviator, prepare to be hooked because it's really simple and super fun - basically, you're there to hold your nerve and watch the multiplier rise, trying to cash out just before the plane flies off

30 Aug 2026 7:00am GMT

AI voice just solved my chaotic grocery lists – is this the breakthrough we’ve been waiting for?

Messy grocery lists might have finally met their match, and no, this isn't your usual "AI is coming…

30 Aug 2026 6:00am GMT

Boba Story Lid Recipes – 2026

Look no further for all the latest Boba Story Lid Recipes. They are all right here!

30 Aug 2026 4:04am GMT

Dice Dreams Free Rolls – Updated Daily

Get the latest Dice Dreams free rolls links, updated daily! Complete with a guide on how to redeem the links.

30 Aug 2026 4:03am GMT

29 Aug 2026

feedTalkAndroid

Why This Japanese Series Is Breaking Every Sexual Taboos—And Moving Viewers Like Never Before

Embarrassing questions we keep to ourselves. Hidden desires we may never admit. That's the sensitive territory explored by…

29 Aug 2026 3:00pm GMT

Beatbot AquaSense X Review: The Pool Cleaner That Cleans Itself

Want a pool robot that takes "hands-free" literally? The Beatbot AquaSense X doesn't just clean your pool, it cleans itself afterwards. We put the full setup through its paces to see if the world's first self-cleaning pool robot lives up to the CES hype.

29 Aug 2026 12:30pm GMT

The world’s first Android Auto trojan turns millions of car radios into a global botnet—experts sound the alarm

Imagine never touching your car's infotainment system, only to find out it has been quietly serving cybercriminals halfway…

29 Aug 2026 6:00am GMT

28 Aug 2026

feedTalkAndroid

LG’s 2026 AI TVs Could Make It Easier To Get Better Quality Viewing

The α11 AI Processor Gen3 headlines LG's IFA 2026 TV lineup

28 Aug 2026 3:05pm GMT

Feeling watched by AI? Here’s how to take back control and remove Gemini from Chrome on Android

Ever feel like your web browser is keeping too close an eye on you? If the Gemini AI…

28 Aug 2026 3:00pm GMT

Insta360’s Link 2 Pro Webcams Get a New Arctic White Finish

Same 4K imaging and AI tracking, just a lighter color option.

28 Aug 2026 2:55pm GMT

Galaxy S26 FE Packs a Better Camera and 7 Years of Updates

It's also the first Galaxy S26 phone to launch running One UI 9.

28 Aug 2026 2:47pm GMT

Jackery’s New Power Station Grows From 1kWh to 11kWh as You Need It

The 1800W power station starts at $749, discounted to $619 through Sept 3

28 Aug 2026 12:48pm GMT

27 Aug 2026

feedAndroid Developers Blog

How WhatsApp Upgraded to Secure, Seamless Sign-In for 1 Billion Users with Passkeys

Posted by Niharika Arora, Senior Developer Relations Engineer, Tracy Agyemang, Product Marketing Manager, Google and Mayank Manuja, Android Engineer, Meta
WhatsApp passkey banner

WhatsApp is the world's largest messaging platform, serving billions of users globally. It is the default communication tool for people across diverse regions, connecting users through private, reliable, and secure messaging.

"What excites me most is the sheer scale of WhatsApp's impact. Even a small improvement to WhatsApp touches billions of users worldwide," says Mayank Manuja, an Android Engineer on the WhatsApp Registration and Access team who led the design and implementation of passkey-based authentication for WhatsApp.

Building for an audience of this magnitude requires navigating a vast range of network conditions, device capabilities, and levels of digital literacy. Recognizing the potential early, WhatsApp committed to adopting passkeys in 2023, becoming one of the first major consumer apps to integrate the technology. By implementing passkeys, WhatsApp aimed to provide a fast, phishing-resistant option that significantly reduces user friction while providing robust protection against account takeovers and credential theft.

Passkey setup walkthrough animation
A user creating a passkey on WhatsApp for faster, more secure sign-ins.

The Decision to Adopt Passkeys

For WhatsApp, offering multiple access methods is key to making it easier for users to stay connected and regain access when needed. Passkeys offer users a streamlined, one-tap login experience that eliminates phishing risks and functions reliably even in regions where OTP message delivery can be inconsistent.

Underneath, passkeys leverage public-private key cryptography to replace manual entry with biometric or screen lock authentication. This workflow drastically improves sign-in speeds by reducing the process to a single tap via a unified, bottom-sheet interface that keeps users engaged within the app's context. The benefits are twofold: passkeys offer users a streamlined login experience while simultaneously providing robust, native protection against phishing attacks. Crucially, they function reliably even in regions where traditional SMS OTP delivery can be inconsistent.

Public-private key cryptography flow
How passkeys are saved and used to authenticate using public-private key cryptography
Passkeys security architecture overview

Having robust and diverse account access methods ensures that users are never locked out of what matters most to them.

Client-Side Integration

From the WhatsApp developer perspective, the Credential Manager API provided a clean, unified interface that abstracted away the complexity of underlying credential providers. Once initial integration flows were mapped out, the API surface became straightforward, with credential creation and retrieval following well-defined request and response patterns. Find the implementation guide in the Android developer documentation.

While the happy path worked from the start, navigating a diverse user base across OEMs, multiple Android versions, and varied device configurations (such as PIN-only versus biometric, or Android 13 versus 14+) surfaced unprecedented edge cases. These included users without a screen lock, unexpected exception types, outdated Play Services, and inconsistent credential provider behavior.

To overcome these hurdles, the WhatsApp and Google teams collaborated deeply and tackled several challenges:

Note: For further guidance, explore the Passkeys best practices blog to learn how to optimize the user experience when adopting passkeys.

Refining the User Experience

Because passkeys were an entirely new concept in early 2023, there were no established patterns for prompting their creation. Through extensive A/B testing, WhatsApp developed a contextual framework targeting users who would benefit most. This strategy continuously evolved: as Android OS flows matured into a streamlined, single-screen experience, WhatsApp simplified its own prompts to avoid redundant or confusing UI.

WhatsApp passkey screen setup
WhatsApp's streamlined, single-screen passkey creation flow

Server-Side Architecture and Cross-Platform Hurdles

On the backend, WhatsApp's server implements the standard WebAuthn/FIDO2 ceremonies. The backend is written in Erlang and calls the Rust webauthn-rs library through a native interface. This Rust library handles signature verification and credential parsing, allowing the internal code to remain focused on orchestration, storage, and product rules like eligibility, rate-limiting, and credential lifecycle.

The server architecture orchestrates these core ceremonies through four primary entry points, paired into Begin and Finish sequences for both Registration and Authentication:

1. Passkey registration

This sequence handles issuing creation options to the client, verifying the attestation once the client acknowledges successful creation, and securely persisting the credential.

The server & client interaction architecture during passkey registration
The server & client interaction architecture during passkey registration

Erlang: Begin Registration

begin_registration(UserId) ->
    Existing = list_credentials(UserId),
    %% reuse the existing user handle, or mint a new one
    {UserHandle, IsNew} = user_handle(Existing),
    %% returns the client creation options and the server-side challenge state
    #{client_safe := CreationOptions, server_only := ChallengeState} =
        webauthn:start_registration(UserId, UserHandle, rp_config()),
    %% excludeCredentials: the user's existing credential IDs, so the device won't re-enroll one
    Options = with_exclude_credentials(CreationOptions, credential_ids(Existing)),
    store_challenge(UserId, ChallengeState),          %% short TTL
    IsNew andalso reserve_user_handle(UserId, UserHandle),
    Options.

Erlang: Finish Registration

finish_registration(UserId, Attestation) ->
    ChallengeState = get_challenge(UserId),          %% must exist and be unexpired
    #{credential_id := CredId, public_key := PubKey} =
        webauthn:finish_registration(Attestation, ChallengeState, rp_config()),
    ok = index_credential(CredId, UserId),            %% map credential_id -> account
    case multi_passkey_enabled(UserId) of
        true  -> add_credential(UserId, CredId, PubKey);      %% append (oldest evicted past the cap)
        false -> replace_credential(UserId, CredId, PubKey)   %% single-passkey mode
    end,
    notify_client(UserId, {passkey_created, CredId}),
    ok.

2. Credential Authentication

Similar to creation, the app server handles the authentication flow by orchestrating the login sequence. This includes verifying the assertion after successful client authentication, and dynamically updating stored credentials whenever WebAuthn signals a refresh is necessary.

Erlang: Begin Authentication

begin_authentication(UserId) ->
    Credentials = list_valid_credentials(UserId),
    #{client_safe := RequestOptions, server_only := ChallengeState} =
        webauthn:start_authentication(Credentials, rp_config()),
    store_challenge(UserId, ChallengeState),          %% short TTL
    RequestOptions.

Erlang: Finish Authentication

finish_authentication(UserId, Assertion) ->
    ChallengeState = get_challenge(UserId),
    Credentials = list_valid_credentials(UserId),
    case webauthn:finish_authentication(Credentials, Assertion, ChallengeState) of
        #{user_verified := true, credential_id := CredId, needs_update := NeedsUpdate} = Result ->
            %% webauthn tells us when the stored credential should be refreshed
            NeedsUpdate andalso refresh_credential(UserId, CredId, Result),
            mark_credential_used(UserId, CredId),
            {ok, CredId};
        _ ->
            {error, not_allowed}
    end.
Step-by-step passkey login experience
The step-by-step passkey login experience on the WhatsApp app.

To know more about server registration, follow the integration guide here.

Advanced Architectural Considerations

Implementing passkeys on the server at scale presented unique challenges, particularly concerning account architecture and device synchronization. Ashish Choudhary from the WhatsApp backend team highlighted the primary hurdles they faced:

Rethinking Cross-Device Synchronization

This robust multi-passkey architecture also allowed WhatsApp to completely rethink cross-platform usability. The standard WebAuthn cross-device flow requires scanning a QR code on one device and authenticating over Bluetooth on another. However, WhatsApp found the Bluetooth dependency unreliable, and users often confused the new QR codes with the existing WhatsApp Web linking process.

Instead of forcing a fragile cross-device transport mechanism, WhatsApp allows users to hold passkeys natively across multiple ecosystems such as Google Password Manager on Android and iCloud Keychain on iOS. When users migrate to a new platform, they simply generate a fresh passkey during their next sign-in. This approach is completely frictionless for the user and operates seamlessly on top of the new multi-passkey server infrastructure.

Looking Ahead

Since launching passkeys, WhatsApp has witnessed robust organic adoption across its vast user base. By transforming the traditional multi-step sign-in process into a single, frictionless biometric gesture, the app has dramatically improved the user experience. Building on this momentum, WhatsApp is now expanding passkey utility beyond initial sign-ins, exploring seamless in-app re-authentication for sensitive account actions like passkey-encrypted backups.

Looking ahead, WhatsApp is actively collaborating with platform partners to pioneer lower-friction credential creation paths, anticipating that barriers to entry will naturally diminish as device biometric capabilities expand.

Recommendation for Developers Building at Scale

For developers preparing to integrate passkeys at scale, the WhatsApp team shares these critical recommendations:

WhatsApp passkey summary diagram

Get Started with Passkeys and Credential Manager

Get hands on with passkeys and Credential Manager on Android using our integration guide and public sample code.

If you have any questions or issues, you can share with us through the Android Credentials issues tracker.

27 Aug 2026 5:00pm GMT

26 Aug 2026

feedAndroid Developers Blog

Elevating app quality: Reducing memory usage and improving device migration

Posted by Raghavendra Hareesh Pottamsetty, GM, Google Play Developer & Monetization

Maintaining a healthy Android ecosystem is a shared commitment where every app and game has a role to play. To help you deliver the premium experiences users expect, Google Play is introducing two new quality requirements: one focused on reducing app memory footprint, and another on providing a secure, seamless device migration experience.

First, to help developers navigate industry-wide hardware constraints and Android's broader memory limits, Google Play is establishing new performance thresholds.

Second, as part of our broader commitment to elevate app quality, we are introducing a new onboarding standard to simplify and secure login during device upgrades.

Reducing app memory usage and optimizing code

The mobile industry is navigating significant hardware supply constraints that are altering device memory availability that over time can negatively impact the user experience. Android is addressing this challenge head-on with broader memory limits that aim to protect the overall user experience from apps using excess memory and causing system-wide slowdowns.

Building on this, today Google Play is establishing performance thresholds to help developers ensure their apps continue to deliver the premium experience users expect. This includes new thresholds across dynamic memory usage, bitmap usage, and code optimization to prevent unexpected on-device performance throttling and app terminations.

Review the thresholds and technical details to better understand applicability differences specific to apps and games, RAM buckets, and process states.

New tools to help you take action

To enable you to proactively discover, investigate, and optimize your app or game to meet the new bad behavior thresholds, we've already begun rolling out new tools in Play Console to get you started.


New memory metrics in Android vitals to identify and resolve memory bloat

Review DEX code optimization insights in Play Console

Later this year, you can expect additional diagnostic tools, including metrics on how long your app spends in each state and deeper insights into the Android Memory Limiter, a feature that prevents individual apps from using too much device memory. Through our ongoing investment in these enhancements, our goal is to help you continuously optimize your footprint and elevate the experience you provide your users.

Enforcement timeline

Starting in February 2027, apps and games must meet their respective bad behavior thresholds for Memory usage (Anonymous RSS + Swap), Bitmap memory usage and DEX code optimization. Similar to existing Android vitals metrics, exceeding thresholds is a strong indicator of degraded app experiences and on-device Android app terminations.

Apps and games that do not meet these thresholds may see reduced app visibility and publishing capabilities on Google Play. Additional details will be provided later this year.

Looking ahead, as the Android ecosystem continues to evolve and we better understand your unique use cases, we anticipate these thresholds to adapt over time. Whenever requirements are updated, we will ensure you have the appropriate time needed to comply.

Providing a secure & seamless device migration experience

When users switch to a new device, moving their apps over should be secure and effortless. To provide a better onboarding experience, we're introducing a requirement for app developers to make log-ins faster and safer during device transfers.

The Zero-Tap Sign-In standard will require any app supporting user sign-in, optional or mandatory, to automatically restore a user's sign-in state when they move from one Android device to another with the Android Restore Credentials API. This API ensures that when a user opens your app on their new Android device for the very first time, they are instantly recognized and securely signed in without additional taps.

Starting in April 2027, Google Play will require apps to meet the Zero Tap Sign-In requirement to maintain full publishing capabilities and optimal visibility in the Play Store.

While games are currently exempt from the Zero-Tap Sign-In requirement, developers should expect dedicated guidance and tailored solutions for complex gaming authentication use cases coming in 2027. For games who support single-account sign-in, we strongly encourage usage of the Restore Credentials API to support zero-tap sign-in. Please visit our help center for more information.

Plan your roadmap: Review Play's requirements

Start preparing for the upcoming enforcement deadlines by reviewing the details of each requirement:

Meeting these quality requirements on Google Play is a crucial step toward building a faster, more reliable experience for our users. We appreciate your partnership and everything you do to keep the Android community thriving.

26 Aug 2026 5:00pm GMT

25 Aug 2026

feedAndroid Developers Blog

Ensuring Safety in the Generative AI Ecosystem: Protecting Users from Non-Consensual Intimate Content

Posted by Ron Aquino, Senior Director, Trust & Safety, Chrome, Android, and Play

At Google Play, user safety and developer success go hand in hand. We continue to see growth in apps with AI generated features, and indeed, adding generative AI into your apps is a great way to unlock incredible creative possibilities. However, AI features also bring new safety challenges - such as the rise of AI-facilitated generation of non-consensual intimate imagery (NCII). Google Play's policies prohibit the facilitation, creation, or distribution of non-consensual sexual content. Harmful applications designed to target, harass, or exploit individuals have absolutely no place on Google Play, and we are committed to enforcing our policies to keep the store a safe space for developers to thrive.

We know that the vast majority of you are dedicated to building positive, ethical tools. To protect both your hard work and our shared user base, we are investing heavily in platform protections, technical defenses, and developer resources to stop abuse.

How we're safeguarding our shared ecosystem

Protecting the platform is a continuous effort. Bad actors attempt to exploit distribution channels, monetization paths, and model boundaries. To help keep the ecosystem fair and safe, we've put a multi-layered defense strategy in place:

Practical best practices for your Generative AI features

To help you build safer apps and have a smoother publishing experience, here are a few straightforward ways to design and test your app, aligned with our Sexual Content Policy and AI-Generated Content Policy.

1. Help us streamline your app review

To maintain the integrity of the Play Store, we are reiterating our enhanced requirements specifically targeting Generative AI applications. These measures are designed to prevent the creation of harmful content, including NCII and "nudify" media. Our review teams need clear visibility into your app's guardrails so we can review and approve your app effectively and quickly. You can prevent unnecessary review delays by:

Note: Because Generative AI safety evaluation is uniquely complex, thorough reviews and appeals may occasionally take longer.

2. Design your app for Safety

Stress-testing your Generative AI app against adversarial prompts - especially those attempting to force non-consensual explicit edits - is essential. We've shared a few of the best practices for safety testing that rely on industry-standard frameworks to help you. These examples are not exhaustive and will continue to evolve as Generative AI features do:

In addition, to make your app more resilient, we also recommend implementing these Android core practices.

Building responsibly, together

AI innovation should always go hand in hand with safety and user trust. Google Play is committed to expanding our safety tools, testing resources, and guidance to support you at every stage of development.

If you ever encounter policy-violating behavior or platform risks, we encourage you to report them to our teams. Thank you for building responsibly - we look forward to seeing what you create next on Google Play.

25 Aug 2026 5:00pm GMT

24 Aug 2026

feedAndroid Developers Blog

AAOS SDV - Secure by Design

Posted by Markus Vill, Software Engineer, Sean Keys, Security Engineer, and Istvan Nador, Software Engineer, Android Auto



At Google, we believe our products should be secure by design, which is why we built the Android Automotive Operating System for Software Defined Vehicle (AAOS SDV) on existing, market-proven platforms, leveraging virtualization technologies like Cuttlefish. While our release announcements focused on the features, this blog post outlines some of the security concepts.

Foundation: Domain Isolation

Virtualization to isolate co-hosted instances

The current trend of consolidating Electronic Control Units (ECUs) into a single chip reduces isolation by running multiple domains side-by-side.

While AAOS SDV instances provide internal isolation mechanisms, it is often preferable to run logical domains independently. For instance, a cluster and an infotainment system have distinct requirements. We use virtual machines to run multiple instances in parallel, ensuring that sharing remains explicit and isolation is the default behavior.

Inherited Android Security

AAOS SDV evolved from Microdroid, a minimalistic Android version optimized for privacy virtual machines (pVM). This lineage provides Android platform engineers with established security features they already know.

Process Isolation & Deny by Default

AAOS SDV follows Android's User ID (UID)-based isolation model to set up a sandbox for each application. Each service runs in a dedicated process with a unique UID to manage access rights, data directories, and other restrictions. We employ Portable Operating System Interface (POSIX) capabilities to strictly limit operations and pair this with Security-Enhanced Linux (SELinux) to enforce a "deny-by-default" posture. This approach restricts each service to the absolute minimum required, meaning missing configurations block access rather than creating an over-permissive system. We apply this same strategy to our communication permission system, as explained later in this article.

Proven Vulnerability Management

AAOS SDV integrates Android's mature security response and vulnerability management infrastructure to identify, triage, remediate, and disclose security findings. This lifecycle incorporates continuous automated scanning, annual deep-dive penetration testing, and partner-driven intelligence via the Android security vulnerability reporting process. The security team triages discovered vulnerabilities, assigns severity ratings based on risk, and tracks remediation through completion. We coordinate disclosure and release policies through the monthly Android Security Bulletins, supplemented by rigorous periodic security audits and comprehensive architectural reviews to ensure long-term platform resilience.

Integrity: Secure Software Delivery

Beyond guaranteeing process isolation, a secure platform must ensure code integrity before execution. We secure software delivery through the following approaches:

Authenticated Software Delivery

AAOS SDV provides two installation methods. First, we install software directly to read-only system, product, or vendor partitions, which validate signatures on every boot. This secures basic system components.

Second, we utilize Android Pony EXpress (APEX) packages for services. Each APEX encapsulates software and its dependencies, treating the package as a partition with mandatory signature validation. In AAOS SDV, APEX treats code signing as a continuous, hardware-enforced contract. APEX ensures malicious code execution is mitigated through four core pillars:

1. Immutable Storage

  • The Mechanism: The Android kernel loops the apex_payload.img file directly as a raw storage device using the read-only loopback, mounting it with the strict MS_RDONLY flag.
  • Why it's more secure: This exposes no write path to the OS because the files are not unpacked onto the vehicle's storage. Even if an attacker gains root privileges, they cannot modify the running APEX code because the file system layer rejects all write commands.

2. Cryptographic Integrity

  • The Mechanism: The cryptographic signature validates a Merkle Tree of the entire file system image.
  • Why it's more secure: The kernel uses per-block dm-verity to verify the signature for every 4KB data block on-the-fly. If an attacker modifies a raw block on the flash memory, the kernel detects the hash mismatch and halts execution immediately.

3. Strict Isolation

  • The Mechanism: This applies the process isolation rules as described in the Process Isolation section to create a sandbox, with the APEX mounted as a dedicated partition under /apex.
  • Why it's more secure: Each service receives its own user and data directory, restricting access unless sharing is explicit. By creating a dedicated partition, Android establishes a dedicated linker namespace, ensuring only explicitly exposed libraries are accessible from non-privileged system daemons, thus minimizing the attack surface.

4. Atomic Recovery

  • The Mechanism: APEX uses an "Active/Backup" design to enable double-buffered rollbacks. The factory-flashed APEX remains on the immutable /system partition, while updates reside on the mutable /data partition.
  • Why it's more secure: If an update fails or appears malicious, the apexd daemon marks it as "failed" during early boot. The system instantly swaps symbolic links back to the /system partition. This atomic recovery helps ensure the system does not remain in a broken state.

Resilience: Memory-Safe Development

Verified loading protects the system from external modification, but platform resilience also depends on how the underlying code is built. For new components developed for AAOS SDV, we prioritized memory safety.

Rust as the primary language

AAOS SDV targets small systems with fast availability requirements; this prevents building on the full Android stack, so we limited our scope to the native framework. To create the required infrastructure for a distributed system, we developed multiple components in addition to existing infrastructure and adopted Rust as the primary language. We also use Rust to develop the business logic of services, helping partners write secure software. By design, Rust leverages memory safety features to help prevent common classes of memory safety vulnerabilities, while supporting team throughput when writing native code.

Distributed Trust: Network & Access Control

Software-defined vehicles require secure interactions between isolated domains. The AAOS SDV mesh provisioning architecture addresses this complexity by cryptographically verifying the version and author of every communication endpoint.

Device and Mesh Provisioning

The AAOS SDV Mesh establishes authentication by mathematically binding the network identity of every component to its actual binary execution state. This model replaces implicit software trust with hardware-rooted verification.

Mesh authentication is designed to be continuous and cryptographic. This prevents scenarios where, for example, a service like a vehicle gateway trusts a compromised infotainment VM just because it has the right IP address.

Hardware-enforced isolation and automated quarantine protocols secure the platform. Peer devices within the SDV mesh use DICE-based authentication and attestation, as detailed in the following section, to help identify and contain unauthorized code execution or configuration tampering.

DICE-based TLS to secure VM-to-VM communication

Grounding the Host Identity in Reality

The Golden Rule of DICE (Device Identifier Composition Engine): If a single line of code in the firmware changes (even a minor update or a malicious exploit), the derived Compound Device Identifier (CDI) changes entirely, generating a completely different Alias Key.

DICE and TLS (Transport Layer Security) integrate to solve the fundamental challenge of zero-trust architecture: authenticating a machine while simultaneously verifying its software integrity.

The combination of DICE's hardware-backed identification and TLS's encrypted handshake allows a receiving machine to verify both the caller's identity and its exact software state.

Traditional certificates only prove possession of a secret; they cannot detect firmware tampering. DICE addresses this via measured boot layering:

  • The Unique Device Secret (UDS): A random cryptographic secret generated during manufacturing. Only the first-stage bootloader can access the UDS; it remains inaccessible to all other software and external interfaces.
  • Layered Measurements (The Compound Device Identifier): The hardware ROM initiates the chain by hashing the UDS with the exact code and configuration of the next firmware layer. This creates a CDI, which then chains sequentially as each subsequent layer boots.

Strict access controls govern service interactions within the AAOS SDV mesh. Just like all AAOS SDV software, these access controls are authenticated, and their integrity is protected at the device level and across devices in the mesh through the DICE-based authentication.

Layered Access Control

AAOS SDV employs a defense-in-depth strategy to enable dynamic vehicle updates without compromising access mechanisms. This model relies on two primary trust layers:

  • Service-level permissions: Define the specific resources a service on a given VM can access or expose across the mesh.
  • VM-level permissions: Define the cross-VM communication boundaries for all services hosted on a specific VM.

This model allows OEMs to balance security with updatability. For non-security-sensitive services, permissive VM-level policies enable installation via lightweight APEX updates rather than full VM redeployments.

Conversely, permissions for security-sensitive signals must be hard-coded into every VM. The tradeoff is that introducing a security-sensitive service to a new VM requires updating the VM-level permissions system-wide. This necessitates an update to all VMs within the mesh.


Conclusion

AAOS SDV extends Android's security architecture to address specific automotive requirements through a secure-by-design approach. By leveraging virtualization for domain isolation and enforcing "deny-by-default" access policies, the platform establishes a resilient environment for software-defined vehicles. Cryptographic integrity is maintained via hardware-enforced, on-the-fly verification of executed code.

The platform integrates continuous security lifecycles, ranging from proactive vulnerability management to hardware-rooted identity verification via DICE. These multi-layered defenses allow OEMs to balance advanced feature updatability with the robust security necessary for modern automotive environments. Technical specifications and implementation details are available on the AAOS SDV Overview page.

24 Aug 2026 4:00pm GMT

19 Aug 2026

feedAndroid Developers Blog

Preparing your app for broader memory limits

Posted by Blair Harmon, Director of Product Management, Android Platform



A great user experience is central to Android's mission, and delivering on that promise requires keeping devices fast, responsive, and reliable. This is why memory optimization is more critical than ever. Across the ecosystem, new devices are maintaining or even decreasing their physical memory capacity in response to memory price increases, yet users continue to expect the same seamless, high-performance app experience.

In Android 17, we introduced per-app memory limits, starting with Pixel devices, to help protect the overall user experience from applications using excess memory and causing system-wide slowdowns. Over the coming year, an increasing number of manufacturers will leverage the Android per-app memory limits across their portfolio of device RAM configurations from 4GB to 16GB+ devices. If your app exceeds these limits, it will be slowed down and may be terminated. Optimizing your app's memory footprint is essential to preventing OS throttling and maintaining a seamless user experience.

In this post, we'll explore how these limits work under the hood, how to measure your memory footprint using new Android vitals metrics, and actionable steps to optimize your app or game.

Understanding Memory Limits

When your app exceeds its memory budget, Android takes progressive action to protect device responsiveness:

  1. zRAM Swapping: If your app reaches its allocated limit, the system forces your app's pages into zRAM (compressed RAM). While zRAM prevents immediate eviction, compressing and decompressing pages adds CPU overhead, which can result in noticeable UI jank and experience slowdowns.
  2. Process Termination: If your app continues to increase its memory usage beyond the zRAM threshold, it will be terminated by the system. To determine if your app session was impacted by these constraints in the field, you can call getDescription() within ApplicationExitInfo. If the system applied a limit, the exit reason is reported as REASON_OTHER and the description string will contain "MemoryLimiter:AnonSwap". You can also leverage trigger-based profiling using TRIGGER_TYPE_ANOMALY to automatically capture heap dumps when the memory limit is reached.

To learn more about per-app memory limits and system enforcement, review the Android 17 App Memory Limits documentation. To test your application on different device configurations use the Memory Limiter adb commands.

Monitoring and Diagnosing Memory Issues

You can't optimize what you can't measure. Identifying memory leaks, excessive heap allocations, and Out-Of-Memory (OOM) crashes across the Android ecosystem requires leveraging complementary monitoring tools:

  • Macro-level health with Android vitals: For broad, population-level visibility without additional overhead, Google Play Console's Android vitals provides essential metrics like Memory Usage (Anonymous RSS + swap) and Bitmap Memory Usage. This gives you a clear snapshot of memory distribution across different process states (foreground, background, user-perceived services, and cached) and RAM class ranges, helping you spot memory outliers.
  • Memory Limiter exits & OOM tracking with Firebase Crashlytics: To stay informed about severe memory degradation before it impacts your key metrics, Crashlytics version 20.1.0 introduces additional debug data to help you catch, prioritize, and fix Out-Of-Memory exceptions and memory limiter kills. Tracking these events alongside custom logs and key-value metadata gives you immediate context into process status when a memory failure occurs.
  • In-field traces with ProfilingManager: For teams able to maintain a performance observability framework, the ProfilingManager API introduced in Android 15 (API level 35) allows your app to programmatically request and collect detailed memory debug artifacts such as Java heap dumps and heap profiles directly from production devices. You can also trigger heap dump captures based on specific system signals, such as TRIGGER_TYPE_OOM and TRIGGER_TYPE_ANOMALY.

Read our documentation to learn more about other memory monitoring techniques.

Summary & What's Next

With Android broadening per-app memory limits across all RAM classes, now is the time to audit your memory footprint:

  1. Prioritize memory optimizations: Prevent your app from being impacted by app memory limits by using best practices.
  2. Monitor memory use: Monitor your app's memory behavior to detect and resolve anomalous behavior.
  3. Optimize your game: Follow the latest guidance for games and complex multimedia apps to maximize memory savings across process states.

Helpful Resources & References

19 Aug 2026 7:00pm GMT

18 Aug 2026

feedAndroid Developers Blog

Tinder cuts app cold starts by 47% with new R8 Configuration Analyzer

Posted by Ajesh R Pai, Developer Relations Engineer, Ulises Uriel Verduzco Diaz, Software Engineer, Tinder, and Tracy Agyemang, Product Marketing Manager


Tinder is on a mission to power and inspire real connections by making meeting easy and fun for every new generation of singles. However, as their Android application codebase grew in size, so did its complexity. Prior to their latest optimization efforts, approximately 70% of the application was not optimized, carrying 17 dex files,including three dedicated just to startup. Although they had enabled R8, much of its optimization potential was blocked due to keep rules, and the team was unable to identify which specific rules were preventing optimization. To reduce startup time and decrease user-perceived Application Not Responding (ANR) errors, Tinder turned to the new R8 Configuration Analyzer to tackle these challenges.

By utilizing the R8 Configuration Analyzer, Tinder successfully identified and removed unintentional optimization blockers. The results were immediate and impactful: Tinder achieved a 47% reduction in app cold starts, shrank their app download size by 28.98% (down to 61.5 MB), and reduced user-perceived ANRs by 28%.

Configuration analyzer

The R8 Configuration Analyzer shows R8 optimization by tracking shrinking, optimization, and obfuscation scores to show available refinement areas. It shows the broad, redundant, or obsolete keep rules, including those from external libraries so that you can analyse the keep rule impact and refine the keep rules.

Key metrics shown in Configuration Analyzer include:

  • Shrinking Score: Code percentage available for R8 shrinking.
  • Optimization Score: Code percentage open to optimization (for example, method inlining, horizontal class merging).
  • Obfuscation Score: Percentage of classes, methods and fields that can be renamed by R8 to decrease size.

Use the analyzer to audit keep rules and their impacts:

  • Find broad rules: Narrow the scope of package-wide rules that restrict R8 optimization, and identify the specific classes, methods, and fields excluded from shrinking, optimization, and obfuscation.
  • Refine rules: Target only specific classes/methods requiring reflection to unlock optimization
  • Remove redundant rules: Remove rules that match zero classes, methods, or fields in your current build.
  • Identical rules: Identical keep rules means rules that target the same classes, fields, and methods or duplicate declarations of keep rule in same or across keep rule files.
  • Find subsumed rules: Clean up specific rules already covered by broader configurations.
  • Identify problematic libraries: Check the combined optimization impact of merged consumer keep rules from all libraries.



R8 Configuration Analyzer report of a sample application

To assist you in using the R8 Configuration Analyzer with agentic tools, we have published an R8 Analyzer skill. This skill optimizes automated development workflows by summarizing the R8 Configuration Analyzer report to display key metrics: optimization, obfuscation, and shrinking scores. It also highlights the five most impactful keep rules, giving you clear insight into what blocks code optimization.

Pinpointing hidden optimization blockers



Prior to integrating the R8 Configuration Analyzer, Tinder's Android app suffered from significant technical debt due to a heavily unoptimized codebase. This lack of optimization directly degraded the user experience, leading to users experiencing slow cold starts

To resolve these issues, the Tinder team utilized the R8 Configuration Analyzer to comprehensively audit their R8 configuration. The analyzer showed the R8 optimization of the codebase was around 28% even with R8 full mode. With R8 Configuration Analyzer, Tinder identified that an in-house library was introducing a broad, unscoped keep rule.

# Prevents optimization in all public classes along with all of their public and protected members

-keep public class * {
    public protected *;
}

This "wide" rule unintentionally covered various dependencies across the entire app, preventing optimization in a large number of classes. Because the over-inclusive rule prevented runtime crashes, developers frequently missed adding new rules for new features that used reflection, allowing hidden issues to compound over time.

By leveraging the insights provided by the R8 Configuration Analyzer, the team successfully traced and analyzed the specific classes affected by the broad keep rule from the library. The team immediately discovered that optimization was being blocked in larger, non-dynamically invoked classes where R8 could do optimization. Refining this specific keep rule allowed Tinder to unlock substantial optimization capabilities, untangle their legacy configurations, and drastically improve their overall optimization numbers, with R8 scores increasing from 28% to 50%, driving immediate performance gains across the application, and the Tinder team is actively working to further improve this figure.

  • Faster Loading: The team achieved a 47% reduction on users experiencing slow cold starts of the app.
  • Smaller Footprint: The App download size went from 86.6MB down to 61.5 MB (28.98% decrease).
  • Improved Stability: User-perceived Application Not Responding (ANR) errors decreased from 0.35% to 0.28%, bringing them significantly closer to the peer median numbers
  • Reduced Complexity: The total number of DEX files was cut down from 17 to 11, including just two startup files.

Beyond these technical performance enhancements, the increased application optimization directly translated into tangible business growth and higher user engagement, particularly in resource-constrained markets.

  • Regional Engagement: Countries where Low RAM devices take a huge portion of the market, presented the largest increase in engagement, and decreasing the ANR rates was key to improving engagement in this vast market.
  • Engagement Growth: Engagement has increased 3% since the increase in app optimization.


Safeguarding future performance with continuous integration

Addressing code minification isn't just a one-time fix; it requires continuous vigilance. Inspired by the massive gains achieved through the R8 Configuration Analyzer, Tinder's Android team proactively integrated optimization monitoring into their daily workflow to prevent regressions.

Tinder's team added a new job in their CI/CD pipeline to report changes in the optimization stats so everyone can see how their contribution is affecting optimization. When advising other developers considering R8 configuration integration, the team emphasizes the importance of auditing internal dependencies. While most popular third-party libraries come with well-defined rules, internal company projects that are considered "stable" might actually be introducing wide rules that negatively impact overall optimization.

Key Takeaways

Faced with a heavily unoptimized codebase and a high volume of DEX files, Tinder needed a way to cleanly audit their app's minification rules. The R8 Configuration Analyzer provided the ideal tooling necessary to identify overly broad internal library rules, the classes affected by the keep rule, allowing the team to confidently optimize their codebase. As a result, Tinder successfully cut cold starts by nearly half, shrank their APK size by over 28%, and established a healthier, more performant foundation for their users, with the team actively working to further improve these numbers.

How to Use R8 Configuration Analyzer

The R8 Configuration Analyzer and its standalone features can be utilized based on your current Android Gradle Plugin (AGP) version:

  • AGP 9.3 Release: The R8 Configuration Analyzer is fully integrated and released with AGP 9.3. When running an R8 release build, the report will be generated in the build/outputs/mapping/release/configanalyzer.html folder.
  • Standalone Gradle Task: AGP 9.3 introduces a standalone Gradle task that allows you to generate the analyzer report without running a full release build, providing a much faster feedback loop when refining keep rules locally:
    ./gradlew :app:analyzeReleaseR8Config
    The report is generated at build/reports/r8/r8-config-analyzer-release.html.
  • Usage on Older AGP Versions: If you are using a version below AGP 9.3, you do not need to migrate your entire AGP version to analyze your configuration. You can update the R8 version independently to 9.3.7-dev or higher by following the Replacing R8 in AGP instructions. To generate the report locally, run your build with the property specified:
    ./gradlew assembleRelease  -Dcom.android.tools.r8.dumpkeepradiushtmltodirectory=<output_directory>

To learn more, see the R8 Configuration Analyzer documentation.

18 Aug 2026 6:00pm GMT

Jetpack XR SDK core libraries reach beta: The next milestone for Android XR

Posted by Amy Zeppenfeld, Developer Relations Engineer, Greg Underwood, Software Engineering Manager, Yasmine Evjen, Senior Product Manager, Android XR




Since introducing the Android XR SDK, developers have transformed their ideas into innovative, immersive experiences for XR headsets and wired XR glasses. As the ecosystem expands, you can more easily take those experiences from preview to production and reach users wherever they are.

Today, we're excited to announce that Jetpack SceneCore, ARCore for Jetpack XR, and XR Runtime have reached beta with Jetpack Compose for XR to follow soon! This means the APIs are stabilizing, making it a great time to start integrating them into your production workflows and creating for Android XR.

Why the Jetpack XR SDK?

The Jetpack XR SDK includes all the tools and libraries you need to build immersive and augmented experiences for Android XR. Whether you're porting an existing 2D app or creating a new 3D XR app from scratch, you can do so using the familiar Android development tools you already know and love.

To support your development, this release focuses on providing the fundamental building blocks across the SDK:

What's new in Beta?

Direct feedback from the developer previews helped shape these beta releases, introducing several important API refinements to ensure these libraries are ready for production.

See the full release notes for each library to check out specific details on naming and API changes.

Get started and provide feedback

To add these dependencies, include the Google Maven repository in your project and add the newest XR libraries to your build.gradle files.

dependencies {
    implementation("androidx.xr.scenecore:scenecore:1.0.0-beta02")
    implementation("androidx.xr.arcore:arcore:1.0.0-beta02")
    implementation("androidx.xr.runtime:runtime:1.0.0-beta02")
    implementation("androidx.xr.compose:compose:1.0.0-alpha17")
}

The ecosystem of Android XR devices that power immersive experiences is expanding, ranging from XR headsets to wired XR glasses. There's never been a better time to start building immersive experiences with the Jetpack XR SDK Beta. Dive in and start building and testing on Samsung Galaxy XR or Android XR Emulator today.

18 Aug 2026 5:00pm GMT

12 Aug 2026

feedAndroid Developers Blog

Enhance your app for the new Pixel lineup: Unveiled at Made by Google

Posted by Fahd Imtiaz, Senior Product Manager, Loryn Hairston, Product Marketing Manager, and Tracy Agyemang, Product Marketing Manager, Android Developer





Made by Google expands what's possible across the Android ecosystem. With the introduction of the Pixel 11 Pro Fold, Pixel Watch 5, and the entire Pixel family, users are moving seamlessly across diverse screen sizes, unique postures, and intelligent experiences. For you, the developer, this represents a massive opportunity: foldable users spend about 14x more than standard phone users. To help you elevate your existing experience without starting from scratch, we're sharing our latest platform guidance alongside real-world examples from developers already putting these features into production.

Deliver adaptive experiences across foldables and expanded displays

The Pixel 11 Pro Fold gives your app a chance to flex its capabilities with an expanded inner display and a standard size outer screen. Building for the foldable form factor requires dropping hardcoded layout rules and designing around available window space. Leveraging Jetpack Compose APIs like Navigation 3 with Scene strategies or our newest layout APIs like Grid and FlexBox allows your layout containers to automatically wrap, span, and reflow. You can also use the experimental MediaQuery API to dynamically adapt your UI to environmental signals like foldable posture, and keyboard states.

Building adaptively requires tracking actual app dimensions rather than physical device size, especially during split-screen and multitasking flows. Using Window Size Classes from the WindowManager library allows your layout to respect folds and hinges as natural content separators.

For instance, Notability leveraged Material 3 Window Size Classes to create a responsive two-pane layout that transitions smoothly between folded and expanded screens. As Ryan Shea, Android Engineering Manager at Notability, shared, tracking the window itself allows their layout and canvas zoom to ensure notes stay fit to the page through every fold, rotation, or split-screen resize, noting that they wanted the app "to feel native at every size, not just stretched to fit."
Notability's quiz UI adapted for expanded screens

Ensuring these transitions feel seamless also requires state preservation across configuration changes. Using ViewModel retains UI state so interactions like scroll position, form inputs, and open dialogs remain uninterrupted when transitioning between inner and outer screens.

Taking this approach, Flo Health used Jetpack Compose state primitives, ViewModel, and Window Size Classes to make their highest-traffic user journeys resilient to rotation, fold/unfold and resizing transitions. As Aleksandr Kolodiazhnyi, Senior Android Engineer at Flo Health, shared, "Android's adaptive guidance turned what looked like a major refactor into a templated rollout," allowing them to adopt Compose primitives without a rewrite, "cutting [their] state-preservation code by roughly 30% while fixing lifecycle and analytics correctness issues that improved the app on every form factor."




To take full advantage of the foldable form factor, leverage FoldingFeature updates to trigger posture-specific layouts. When a user partially folds their device into tabletop posture, you can split your UI automatically by placing primary controls on the lower display and main content or viewfinders on the upper display.

Handling camera previews across foldable state changes, requires managing orientation shifts carefully. Migrating to the CameraX library ensures automatic handling of sensor rotation and display scaling across screens, while existing Camera2 codebases can also achieve stability using the CameraViewfinder library. These camera and display capabilities allow you to power dual-screen previewing and high-resolution rear camera selfies with minimal custom logic.

Prepare your app for these form factors today by exploring our complete adaptive development guidance at Build adaptive apps.

Bring delightful, gesture-driven experiences to the wrist

The new Pixel Watch 5 is here, and we've optimized it to take advantage of the intelligent, power-efficient, touch-free convenience of Wear OS 7. Thanks to system-wide performance optimizations and a collection of new features built to help users complete tasks efficiently, you can provide rich experiences that require only a single user action to complete.

The one-handed gestures framework provides a convenient way for users to interact with their watches without needing to touch the screen with their opposite hand. Starting with the 1.7 beta release of Compose for Wear OS 7, you can seamlessly integrate one-handed gesture control into your Wear Compose apps with simple physical inputs on the watch-wearing arm, like a double-pinch or wrist turn.

Spotify is adopting this framework to make controlling media more effortless. By mapping Wear OS gesture events directly to the media player state, users will be able to pause or resume playback using a simple double-pinch, keeping music controls accessible even when their hands are full.


Pause Spotify media with a pinch gesture

Wear OS 7 also brings Live Updates directly to the wrist to surface real-time information like live sports scores, workout progress, and delivery status, which can also appear in the At-a-Glance surface on Pixel Watch 5. For example, Just Eat uses Live Updates to keep users informed on order arrival times at a glance. You can publish updates locally from your watch app or leverage phone notification bridging on supported devices to deliver real-time tracking across screens.

Live Updates from Just Eat delivering real-time status and delivery ETAs at a glance

You can also extend glanceable interactions across watch surfaces on Wear OS 7 by using Wear Widgets, powered by Jetpack Glance and RemoteCompose. Wear Widgets with Compose offer greater expressiveness and consistency than the old Tiles framework, and the two available widget layouts-small and large- align perfectly with the 2x1 and 2x2 formats on mobile, ensuring your designs feel cohesive across devices.

On top of all these great new features, Wear OS 7 delivers up to a 10 percent improvement in battery life over Wear OS 6, making the Pixel Watch 5 a truly indispensable all-day companion for your users.

To get started developing for Wear OS 7, use the new emulator, and check out all of our Wear OS resources and guidance at Build apps for the wrist with Wear OS.

Unlock on-device intelligence with Gemini Nano 4


Pixel 11 devices are built to run Gemini Nano 4, bringing fast, responsive, on-device intelligence to the hardware. By running AI workflows directly on device, you can offer low-latency, real-time interactions that feel instant and integrated without needing round trips to the cloud.

Through the ML Kit GenAI Prompt API, you can send natural language requests directly to Gemini Nano on device. The model supports over 140 languages, better multimodal understanding, and much more. Build intelligent on-device features using advanced capabilities like structured output and thinking mode.

Build smart capabilities into your app using our self-service tools and Gemini models.

Shape the next generation of experiences for the Pixel ecosystem today

Made by Google showcases what's possible when hardware and software evolve together, and you are at the center of that innovation. You can begin optimizing your apps today by exploring our updated adaptive guidance, creating glanceable experiences for Wear OS 7, and integrating on-device AI with ML Kit.

To help you implement these updates even faster, you can now leverage Android skills, which provide AI-optimized instructions for agents and tools. Whether you are using Gemini in Android Studio or running the Android CLI through other agents, Android skills give your AI tools the context needed to execute complex workflows automatically. For instance, you can prompt your agent with the CameraX skill to handle camera display scaling across foldables, or use the Adaptive skill to set up dynamic Compose layouts without additional manual work.

Take advantage of these new surfaces, accelerate your workflow with agentic tools, and share your latest builds with the Android community! Head over to developer.android.com to access full documentation, explore the Android skills GitHub repository, and start building today.







12 Aug 2026 7:00pm GMT

Bring one-handed gestures to your Wear OS app

Posted by Chiara Chiappini, Developer Relation Engineer, Android Developer Relations



One-handed gestures offer a convenient and touch-free way for users to interact with their watches, enabling them to perform key actions using only the hand on which the device is worn.

First introduced on Pixel Watch with Wear OS 6.1, one-handed gestures made quick interactions effortless, such as starting and stopping a timer, accepting calls, and controlling media.

Now, with Wear OS 7, we're expanding this functionality with a new Gestures framework that allows OEMs to map gestures to primary actions and dismissals, and an API to bring gesture control to the developer community.

Starting with the 1.7 beta release of Compose for Wear OS, you can seamlessly integrate gesture control into your Wear Compose apps. To use this release, upgrade your Wear Compose dependency to:

androidx.wear.compose:compose-material3:1.7.0-beta01

Designing for one-handed interaction

The one-handed gestures framework is designed around two primary interaction patterns that allow users to take action without touching the screen:

These gestures are currently available on Pixel Watch 3 and newer, and the Wear OS gesture framework is available to all Wear OS device manufactures to adopt.

Check out our new design guidance for integrating one-handed gestures into your Wear app.

Integrating gestures with Compose on Wear OS

To provide seamless gesture support in Wear OS 7, we are introducing a new Modifier.oneHandedGesture that you can apply to any existing interactive composable to make it gesture-aware.

Implementing gestures with Compose on Wear OS requires these steps:

  1. Define the gesture configuration. Start by using rememberOneHandedGestureConfiguration to define the nature of the interaction. This configuration dictates the basic behavior by providing the GestureAction (e.g. tracking a primary pinch or a dismiss wrist flick).
  2. Initialize the indicator state. Depending on your UI component, initialize a specific state object, such as OneHandedGestureClickIndicatorState for buttons or OneHandedGestureScrollIndicatorState for scrollable lists. This state is used to coordinate visual feedback between the gesture detection modifier and the visual UI indicators, seamlessly managing visibility, timing, and animations.
  3. Apply Modifier.oneHandedGesture to your interactive component. You'll pass in your configuration and state, and you'll provide standard callbacks: onGestureAvailable to activate the visual hint when the system prepares the gesture, and onGesture to execute your action when the gesture happens.

The following sample shows how those three steps translate into code when configuring an IconButton:


val gestureConfig = rememberOneHandedGestureConfiguration(action = OneHandedGestureAction.Primary)
val indicatorState = remember { OneHandedGestureClickIndicatorState() }
val coroutineScope = rememberCoroutineScope()

OutlinedIconButton(
    onClick = onPlayPauseButtonClicked,
    modifier = Modifier.touchTargetAwareSize(IconButtonDefaults.LargeButtonSize)
        .oneHandedGesture(
            gestureConfiguration = gestureConfig,
            interactionSource = interactionSource,
            onGestureLabel = "play or pause",
            onGestureAvailable = { 
                coroutineScope.launch { indicatorState.showIndicator() } 
            },
            onGesture = onPlayPauseButtonClicked,
        ),
) {
    // button content goes here
    // See "Guided discovery with gesture indicators" section of this post for recommendations on adding a gesture indicator.
}

The GestureAction.Primary can also be used to scroll when the content is the end goal of the user journey, or there is a gesture actionable button off screen that the user can scroll to. Some examples include:


val scrollGestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
val scrollIndicatorState = remember { OneHandedGestureScrollIndicatorState() }
val coroutineScope = rememberCoroutineScope()

TransformingLazyColumn(
    state = scrollState,
    contentPadding = contentPadding,
    modifier = Modifier
        .fillMaxSize()
        .oneHandedGesture(
            gestureConfiguration = scrollGestureConfig,
            onGestureLabel = "scroll",
            onGestureAvailable = { 
                coroutineScope.launch { scrollIndicatorState.showIndicator() } 
            },
            onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) }
        )
) {
    // list content goes here
    // See "Guided discovery with gesture indicators" section of this post for recommendations on adding a gesture indicator.
}

Guided discovery with gesture indicators

To help users learn which gestures are available, gesture indicators work as hints to help discovery about which gestures are available on a screen.

These hints provide animated cues that inform users where they can perform a gesture. The framework manages the cadence and appearance of these hints, ensuring that they are helpful without being intrusive. System settings let users change the cadence to something less frequent if desired.

To integrate with hints, the API provides the following gesture indicator components:

The following example shows how to use the OneHandedGestureClickIndicator for a Button. See another example for using the OneHandedGestureScrollIndicator in our guidance.


val gestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
val indicatorState = remember { OneHandedGestureClickIndicatorState() }
val coroutineScope = rememberCoroutineScope()

OutlinedIconButton(
    onClick = onPlayPauseButtonClicked,
    modifier = Modifier.touchTargetAwareSize(IconButtonDefaults.LargeButtonSize)
        .oneHandedGesture(
            gestureConfiguration = gestureConfig,
            interactionSource = interactionSource,
            onGestureLabel = "play or pause",
            onGestureAvailable = { 
                coroutineScope.launch { indicatorState.showIndicator() } 
            },
            onGesture = onPlayPauseButtonClicked,
        ),
) {
    OneHandedGestureClickIndicator(
        gestureConfiguration = gestureConfig,
        indicatorState = indicatorState,
    ) {
        val icon = if (playerUiModel.playbackState.isPlaying) Icons.Filled.Pause else Icons.Filled.PlayArrow
        Icon(icon, contentDescription = "Play or Pause")
    }
}

Sample app showing gesture hint for media controls

We are already seeing early adoption of these APIs from partners like Spotify, who are using one-handed gestures to make music control more seamless on the go. By adopting the Modifier.oneHandedGesture into their Wear OS app, Spotify allows users to play or pause their music with the primary gesture action, which on Pixel Watch devices is the double-pinch gesture. This action triggers the same behavior as the physical play/pause button, and the user doesn't need to touch the screen.

.
Spotify app with gesture integration

Bring one-handed gestures to your app

You can begin experimenting with one-handed gestures today in the 1.7 beta release of Compose for Wear OS.

Ensure your app is running on Wear OS 7, which provides the underlying platform support for gesture detection. Check out our new one-handed gestures developer guide to see how you can start building more convenient experiences for your users.

12 Aug 2026 5:00pm GMT

What's new in the Jetpack Compose August '26 release

Posted by Nick Butcher, Product Manager, Jetpack Compose


Today, the Jetpack Compose August '26 release is stable! This release brings version 1.12 across core Compose modules (see the full BOM mapping), introducing rich visual APIs like Mesh Gradients and Wide Color Gamut (WCG) support, structural layout features like named areas in Grid, seamless integration with Android's Credential Manager, and significant testing and performance improvements.

To update your project to today's release, upgrade your Compose BOM version to 2026.08.00:

implementation(platform("androidx.compose:compose-bom:2026.08.00"))

Breaking Changes

AGP & Compile SDK: Compose 1.12 updates compileSdk to API 37, requiring a minimum AGP 9.1.1. As a reminder, Compose will always target the latest compileSdk. Learn more about this change here.

Modifier.onFirstVisible() is deprecated: Migrate to Modifier.onVisibilityChanged(), which provides more precise visibility threshold tracking.

Graphics

Mesh Gradients

Compose 1.12 introduces MeshGradientPainter to help you create multi-point, organic color gradients.



val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

For more information and examples, see the documentation.

Wide Color Gamut & HDR Support

Modern displays offer extended color fidelity and higher dynamic range. In Compose 1.12, full pipeline support for Wide Color Gamut (P3) and HDR rendering has been enabled across Compose graphics, paint, and shaders. Colors defined in non-sRGB color spaces (such as Display P3) are preserved through to platform rendering without color clamping. Colors will safely fall back to sRGB if they use an unsupported color space (e.g. CieXyz, CieLab, or Oklab), rely on a color space on an unsupported Android version (e.g Bt2020Hlg on Android 13 and below), or if the app is running on Android 9 (API 28) and below.

Other notable changes:

  • LayerOutsets was added to GraphicsLayer & Modifier.graphicsLayer, which you can use to increase the visual bounds of the layer beyond its measured size. Apply LayerOutsets to avoid the implicit clipToBounds behavior when the layer is promoted to an offscreen buffer.

Styles

At Google I/O, we shared our early vision for the Compose Styles API-a unified, performant way to style components. Since then, we have continued building the underlying architecture to guarantee strict type safety and predictable correctness, and to support building custom design systems.

To ensure we get this foundational layer correct, the API will remain experimental, and you can expect breaking changes.

Runtime Optimizations

Keyed SideEffect Overload

SideEffect now supports key arguments, which lets you fire one-shot side effects whenever specific keys change. This can lead to better performance compared to using a LaunchedEffect or DisposableEffect when you don't need the coroutine or dispose block. SideEffect is up to 90% faster than LaunchedEffect and around 20% faster than DisposableEffect. Note that SideEffect runs its effect before DisposableEffect and LaunchedEffect, so use caution if migrating existing effects to this API, especially for LaunchedEffects that rely on being dispatched to start after the current frame is completed.

@Composable
fun AnalyticsTracker(userId: String, screenName: String) {
    SideEffect(key1 = userId, key2 = screenName) {
        analytics.logScreenView(userId, screenName)
    }
}

Animation

DeferredTargetAnimation has graduated out of experimental status.

Interactive Two-Stage Transitions

New composables: DeferredAnimatedContent and DeferredAnimatedVisibility allow creating delightful two-stage transitions, e.g. for predictive back gesture tracking.

Manual animation control: During a transition's deferred phase, animated properties (like scale or offset) can now be manually manipulated in real-time (e.g., tracking a swipe gesture).

Seamless handoff: Once the deferred phase ends, the transition engine takes over and performs a seamless handoff, including velocity transfer, to the automatic transition.

Shared element support: A new permitTransformDuringDeferredTransition flag in SharedContentConfig controls whether shared elements visually transform along with their parent containers during the deferred transition phase.

val state = remember { DeferredTransitionState(initialScreen) }
val transition = rememberDeferredTransition(state)

if (predictiveBackInProgress) {
    state.defer(targetScreen)
} else {
    state.animateTo(targetScreen)
}

transition.DeferredAnimatedContent(
    targetState = targetScreen,
    mutableTransformSpec = {
       MutableContentTransform {
           // Manually manipulate properties during the deferred phase
           initialContentTransform { scale = swipeProgress }
       }
    }
) { screen ->
    ScreenContent(screen)
}

Below are two demos of use cases where a gesture-driven animation is handed off to a triggered animation:



Text, Input & Platform Integrations

Editable Text Formatting

New APIs offer rich-text formatting for editable text in BasicTextField. You can now programmatically apply and manipulate inline character and paragraph formatting using SpanStyle and ParagraphStyle via the new addStyle() method inside a TextFieldBuffer scope (such as inside textFieldState.edit { ... } or an InputTransformation). Additionally, TextFieldBuffer provides getSpanStyles() and getParagraphStyles() APIs that return TrackedRange objects, allowing you to read, update, or remove applied styles. To complement formatting creation, TextFieldState now exposes a read-only textStyles property for querying active styles across ranges, while TextFieldBuffer provides originalTextStyles to inspect formatting state prior to an edit. Text formatting and custom annotations are persisted across configuration changes.

val state = rememberTextFieldState("Formatted text in Compose 1.12")

// Apply bold and color styles to a range of text
state.edit {
    addStyle(
        SpanStyle(fontWeight = FontWeight.Bold, color = Color.Blue),
        start = 0,
        end = 9
    )
}

// Query active styles from TextFieldState
val currentStyles = state.textStyles

Text Selection

A new SelectionState API provides programmatic control and observability over text selection within a SelectionContainer. Hoisting a SelectionState object via rememberSelectionState() and passing into SelectionContainer exposes selectedTexts as a reactive list of AnnotatedStrings and provides methods like selectAll(), clear(), select(TextRange), and extendSelectionByWord().

Additionally, use getSelectableTexts() to retrieve all selectable text items in layout order and select text across composables in the SelectionContainer using a global range.

@Composable
fun ProgrammaticSelectionExample() {
    val selectionState = rememberSelectionState()

    Column {
        Button(
            onClick = { selectionState.selectAll() },
            modifier = Modifier.disableSelectionClearOnTap()
        ) {
            Text("Select All")
        }

        SelectionContainer(state = selectionState) {
            Text("Text content to be selected programmatically.")
        }
    }
}

Credential Manager Integration

Compose text fields now natively integrate with Android's Credential Manager (API 34+) via the Autofill framework (below API 34 is handled by androidx.credentialslibrary). By attaching the new credentialRequest semantics property with CredentialRequestData, text inputs can prompt passkeys, saved credentials, or sign-in requests directly within the user input flow.

@Composable
fun LoginField(textFieldState: TextFieldState) {
    val credentialData = remember {
        CredentialRequestData(
            // Specify Credential Manager request options
        )
    }

    BasicTextField(
        state = textFieldState,
        modifier = Modifier.semantics {
            credentialRequest = credentialData
        }
    )
}

Other notable changes:

  • Support for font variation settings in downloadable fonts.
  • Enabled auto-scrolling when dragging text selection beyond the viewport in SelectionContainer.
  • Added support for automatic interaction sounds (clicks and focus navigation) to Compose components, with a new SoundEffectOnInteraction composable to allow opt-out. Note that as a consequence of this change, semantics click listeners must now be called from the main thread, which may affect a small number of test cases.
  • KeyboardType now includes Date, Time, DateTime, and SignedDecimal.
  • BasicSecureTextField now uses TextObfuscationMode.System by default, while RevealLastTyped serves as an absolute override.

Layout Enhancements

Named Areas in Grid Layout

Building complex 2D layouts is now easier with named areas in the @Experimental Grid component. Rather than managing numeric column and row indices across items, you can define semantic regions in your GridConfigurationScope and position composables by area name.

@OptIn(ExperimentalGridApi::class)
@Composable
fun DashboardLayout() {
    Grid(
        config = {
            area("header", row = 0, column = 0, rowSpan = 1, columnSpan = 2)
            area("sidebar", row = 1, column = 0)
            area("content", row = 1, column = 1)
            gap(16.dp)
        }
    ) {
        HeaderSection(modifier = Modifier.gridItem(areaId = "header"))
        NavigationSidebar(modifier = Modifier.gridItem(areaId = "sidebar"))
        MainContentView(modifier = Modifier.gridItem(areaId = "content"))
    }
}
For more information, see the documentation.

Performance

As with every release, we continue to invest in Compose's performance to ensure that the framework helps you to build beautiful, performant apps. In this release we've focused on improving startup performance and are now seeing Time to Initial Display (the time it takes for an app to produce its first frame) that is comparable to Views in our benchmarks.


Testing & Tooling Upgrades

Test Synchronization

Compose 1.12 introduces new test APIs designed to reduce test execution times and eliminate flakiness during state sampling:

  • hasPendingWork: Passively checks if the UI has pending work without advancing the clock, which is ideal for manual animation loops.

  • runWithoutImplicitWait: Temporarily disables implicit synchronization when stepping through manual clock frames (e.g. animation tests).

  • @Test
    fun testAnimationStateFast() {
    
    composeTestRule.mainClock.autoAdvance = false
        
        while (composeTestRule.hasPendingWork()) {
            composeTestRule.mainClock.advanceTimeByFrame()
            composeTestRule.waitForIdle()
            
            composeTestRule.runOnUiThread {
                composeTestRule.runWithoutImplicitWait {
                    // This is most effective when querying multiple nodes in a single frame. 
                    // It prevents the redundant synchronization overhead that would 
                    // otherwise occur on every individual query.
                    val box1 = composeTestRule.onNodeWithTag("Box1").fetchSemanticsNode()
                    val box2 = composeTestRule.onNodeWithTag("Box2").fetchSemanticsNode()
                    
                    assertThat(box1.boundsInRoot.right).isAtMost(box2.boundsInRoot.left)
                }
            }
        }
    }

    Other notable changes:

    • The captureToImage API now allows you to capture a popup or dialog together with its anchor in a single bitmap.
    • Added onRootWithViewInteraction to scope Compose semantic searches to specific Android Views. This simplifies testing hybrid UIs, such as RecyclerViews, without requiring unique test tags in production code.
    • @PreviewWrapper annotations can now be applied to custom @MultiPreview classes, enabling reusable preview setups (such as custom themes) across multiple components.

    Happy Composing!

    Compose 1.12 makes app development easier and more expressive than ever, with mesh gradients, wide color gamut support, downloadable variable fonts, Credential Manager integration, and faster testing tools. As always, we value your input, so please share your feedback on these changes or what you'd like to see next on our issue tracker. Happy composing!


12 Aug 2026 4:00pm GMT

11 Aug 2026

feedAndroid Developers Blog

Media3 1.11 - What's new?

Posted by Toni Heidenreich, Software Engineer, Android


Media3 1.11 is out. Powering the vast majority of top Android media apps, this release brings new features, bug fixes, and improvements across playback, editing, and UI components. We're expanding our Jetpack Compose UI modules with customizable Player slots and easy to use defaults, interactive gestures, state observers, and short-form video preloading using PlayerPool. We also modernized the Media3 Cast integration with SystemUI Output Switcher support, introduced a new Ktor HTTP client network extension, and added new muxing utilities for Ogg and WAV files.

Read on for key highlights, and check out the full release notes for a comprehensive list of changes.

Playback UI and Compose

With Android becoming Compose-first, we are continuing to expand the media3-ui-compose and media3-ui-compose-material3 modules. This update introduces more granular control over your player layout, richer interaction patterns, and deeper integration with Material3.

Customizable Player layout

The Material 3 Player Composable now supports dedicated content slots for topControls, centerControls, bottomControls, and errorOverlay. You can drop in your own Composables or use the ready-made defaults published in PlayerDefaults:

Player(
  player = player,
  topControls = { PlayerDefaults.TopControls(player) },
  centerControls = { PlayerDefaults.CenterControls(player) },
  bottomControls = { PlayerDefaults.BottomControls(player) },
)

The Player Composable also integrates FocusRequester support, enabling seamless D-pad and keyboard navigation on Android TV, foldables, and desktop environments.

Example for a Composable Player with customized controls

Gestures and playback speed control

PlaybackSpeedState now provides a fast-forward/slow-motion API. The demo-compose app showcases this with a long-press gesture to fast-forward playback and seeking with double tap. Combined with the ProgressSlider introduced in 1.10, the Compose player UI now offers rich touch and gesture interactions out of the box.

Short-form video preloading with PlayerPool

For apps with sliding-window media feeds (for example, short-form vertical video), managing multiple ExoPlayer instances efficiently is a common challenge. Media3 1.11 introduces PlayerPool (in common-ktx) and rememberPooledPlayer (in ui-compose) to handle player recycling and preloading automatically.

The new ShortFormPlayerScreen in demo-compose shows this in action, a vertically paging feed where players are pooled, preloaded, and seamlessly recycled as the user scrolls.

MiniController

A new MiniController Composable in media3-ui-compose-material3 provides a compact playback bar displaying the current item's title, artist, artwork, and progress alongside play/pause controls. As all our default Composables in media3-ui-compose-material3, the MiniController supports Material3 Dynamic Color integration, allowing it to automatically adapt to the user's wallpaper theme.This is ideal for persistent bottom-sheet or mini-player affordances, for example while the user browses content or during active Cast sessions.

The Media3 MiniController showing album art, media metadata and basic controls

Expanded state holders for metadata and errors

We added several new reactive state holders to media3-ui-compose:

  • rememberCurrentMediaItemState - observe metadata about the currently playing item
  • rememberPlaylistState - observe the full playlist and active indices
  • rememberErrorState - track playback errors, with a matching ErrorText Composable and default ErrorOverlay in Material3

We'll continue working on new additions and more customization options in upcoming releases. Please share your thoughts on the project issue tracker.

Modernized Cast integration

Media3 1.11 updates the Cast extension with programmatic configuration options and support for OS-level routing.

CastParams and SystemUI Output Switcher

You can now configure the Cast extension using CastParams:

val castParams = CastParams.Builder()
  .setShowSystemOutputSwitcherOnCastButtonClick(true)
  .build()

Cast.getSingletonInstance(context).initialize(castParams)

Setting setShowSystemOutputSwitcherOnCastIconClick(true) configures the MediaRouteButton to open Android's native SystemUI Output Switcher on supported platform versions, providing a unified output picker experience.

Reactive MediaRouteButton state in Compose

Apps using Jetpack Compose can now easily add the Media routing button (also known as Cast button), which automatically observes the dialog state and updates accordingly. No further logic needed when used together with Media3's CastPlayer!

@Composable
fun TopAppBarWithCast() {
  Row {
    Text(text = "App Title")
    MediaRouteButton()
  }
}
Media3 media route button in an app launching the default output switcher dialog

Core playback and session enhancements

Eclipsa Video - HAGC dynamic HDR metadata (API 37+)

Eclipsa Video promises a more consistent HDR experience across devices, with a consistent baseline HDR white, adaptive headroom depending on the screen and the surroundings, ensuring the creative intent is preserved on all devices.

ExoPlayer now supports playback of the necessary HAGC (ST 2094-50) timed metadata for progressive media (MP4, Matroska). The player automatically merges HAGC metadata tracks with the associated video track and delivers the metadata out-of-band to the decoder on API 37+ devices. On older devices, ExoPlayer seamlessly falls back to providing a standard HDR playback experience without the adjustments.

Illustration to show benefits of Eclipsa Video HDR, like more consistent color contract

New Ktor HTTP client extension

A new media3-datasource-ktor extension module provides KtorDataSource, backed by the Ktor HTTP stack. This offers a Kotlin-first, coroutine-friendly alternative to the existing Cronet and OkHttp data source modules.

Asynchronous MediaSession connections

MediaSession.Callback now includes onConnectAsync(), which lets you process controller connection attempts asynchronously - for example, to verify authorization before accepting a connection. You can return an immediate Future with Futures.immediateFuture(ConnectionResult) for the same behavior as the existing onConnect.

override fun onConnectAsync(
  session: MediaSession,
  controller: MediaSession.ControllerInfo
): ListenableFuture<MediaSession.ConnectionResult> {
  return authenticateControllerAsync(controller)
}

Safer MediaSession defaults

For apps that don't override onConnect or onConnectAsync in MediaSession.Callback, the library now defaults to a more secure configuration. Specifically, session data is no longer shared by default with untrusted controllers, meaning third-party or non-system apps lacking notification access are restricted from accessing session data unless you explicitly implement these callback methods to authorize the connection.

New Muxer implementations & container parsing

OggMuxer and WavMuxer

We've added two new dedicated muxers: OggMuxer for muxing OPUS and VORBIS streams into standard .ogg files, and WavMuxer for generating uncompressed and floating-point PCM .wav audio files.

Container parsing and track references

  • MP4 Track References (tref): Mp4Muxer.addTrackReference allows linking dependent metadata or aux tracks to primary video streams.
  • Chapter Extraction: QuickTime and Nero chapter from MP4 files (.m4a, .m4b), and Matroska chapters, are now extracted as Chapter metadata entries for audiobook and podcast navigation.

Please use the issue tracker to report any bugs, or if you have questions or feature requests. We look forward to hearing from you!

11 Aug 2026 4:00pm GMT

06 Aug 2026

feedAndroid Developers Blog

Inside Android Skills - Built for deprecation

Posted by Jose Alcérreca, Developer Relations Engineer, Android Developer Relations

We released the official Android Skills in April, and the response surpassed all our expectations. In this blog post, I'll address some of the feedback we received, explaining the philosophy and methodology behind the project. Hopefully, this will also help you understand what happens behind the scenes when you install and use skills, allowing you to make better use of tokens and your own time.

Why are there so few official skills?

Currently, we only consider new skills when there's a verifiable knowledge gap in state-of-the-art (SOTA) models. Put simply: you don't need to teach the model what it already knows. (Though there are a few exceptions-read on!)

We've released around 20 official skills so far, and they intentionally target highly specific, fast-moving areas that standard models aren't fully grounded on yet-things like AGP 9, Navigation 3, advanced Camera APIs, and Perfetto SQL.

What about core, more general, skills? Every installed skill injects 100-200 tokens into the baseline context of every task you start. If that skill actually activates, that count can quickly jump into the thousands. In most cases, hoarding basic skills is both counterproductive and expensive. Before installing a skill for writing basic Kotlin or Compose, consider if your LLM of choice really needs it, or if it knows those topics well enough already.

Evaluating skills

Before their release, each skill is tested against a comprehensive set of evals that prove that the skill delivers clear value. These evals should pass when the skill is active, and fail otherwise. Evals are to skills what integration tests are to code.

timeout_s: 1200
repository:
  url: [redacted - internal git repo]
  working_dir: wear_compose_m3_empty_app
category_ids:
  - wear
prompt: |-
  Add a horizontal pager to MainActivity.kt. Have three pages in the pager. Each page should contain
  the text "Page 1", "Page 2", and "Page 3" respectively in the center of the screen.
commands:
  build:
    - ./gradlew assembleDebug
acceptance_criteria:
  project_builds: true
  llm_diff_judge:
    - Must use `HorizontalPagerScaffold`.
    - Each page should use `AnimatedPage` to wrap a `ScreenScaffold`.

Example eval that checks the correct implementation of a horizontal pager on a wear app

At a minimum, we test the skill in Android Studio using the latest Gemini Flash model. Depending on the skill, we also ensure compatibility with other models such as Gemini Pro and other agents such as Antigravity, and third-party systems.

All of the evals run with access to the Knowledge Base, so if the information is in the documentation, and models decide to search for it, we don't publish a skill for it.

Using the Android Knowledge Base (Android Studio or Android CLI)

If you develop Android apps, you should always use the Android Knowledge Base to have access to the official documentation. If you use the agent in Android Studio, it's already available as a tool, but if you use another agent, install Android CLI. Among other things, it contains the docs command, which gives your agent access to the official Android documentation. Having a single tool is much more efficient than installing hundreds of skills.

If your model is acting overconfident, and you want it to consult the documentation more often, a very common way to motivate it is to add "Always consult the official Android documentation when dealing with Android APIs" to your AGENTS.md file or equivalent. Of course, you can also force this by asking the agent to check the documentation directly in your prompts.

Why are pull requests disabled?

Because our evaluation framework depends on internal infrastructure that cannot be open-sourced, we are unable to accept direct pull requests for new skills-without this infrastructure, we would have no way to re-evaluate incoming PR changes. However, we actively monitor community feedback. If you want to report a bug, suggest an optimization, or request a new official skill, please file an issue!

When do core or basic skills make sense?

While SOTA models generally don't need basic skills, there are some scenarios where enabling core or community-built skills adds real value. For example:

Where can I find core skills?

The Android community has your back. Chris Banes has a comprehensive collection of skills for Compose and Kotlin, Ivan Morgillo published a skill that audits Compose projects, and Jaewoong Eum created two on testing and performance.

Always download skills from reputable sources! I personally wouldn't trust repositories containing dozens or hundreds of Android skills as they're probably AI-generated and untested, and they could even contain malicious or biased instructions. Also, don't install general software engineering skills blindly; a lot of them are tailored for web development.

Goal: deprecation

Loosely paraphrasing Karpathy: Skills of today will be in the models of tomorrow. As SOTA models keep improving, we expect skills to be obsolete, especially those built around new APIs. To figure out when to retire them, we run our evals when new models drop. If they pass, we'll keep them around for a few months until most users have transitioned over.

06 Aug 2026 4:00pm GMT

29 Jul 2026

feedAndroid Developers Blog

Delivering safer, age-appropriate experiences on Google Play

Posted by Paul Feng, VP of Product Management, Google Play





Providing a safe online experience and protecting users from harm is a top priority at Google Play. We take this responsibility seriously and have been investing continuously to offer baseline protections on our platform while also empowering parents with the tools they need to make decisions for their families. Importantly, we also want to empower Play developers with the capabilities to deliver age-appropriate experiences based on their app's content.

To support this, today, we are taking another big step in our ongoing partnership with parents and developers by announcing the expansion of the Google Play Age Signals API to all Play developers globally. Building on current availability in Brazil, we will expand this experience first to users in Australia and Canada by mid-August, with a full global rollout to all users later this year.

Empowering developers to create age-appropriate experiences

The Play Age Signals API is a privacy-preserving tool that puts parents in the driver's seat allowing them to share their child's age range (e.g. 16-17) directly with apps. It also enables adults to easily share their age when prompted by the app developer. In turn, developers receive the signals they need to tailor their own in-app safety experiences and content for users in an age-appropriate way.

We want to give developers the ability to choose the right protections for the nature of their app. A weather app, for example, shouldn't need the same safety settings as entertainment or media apps. Rather than enforcing one-size-fits-all rules, we give developers the flexibility to choose how they integrate safety signals. With this reliable signal, you retain complete agency to tailor your app's content, features, and settings to match your audience.

Users have a choice to share their age range in a privacy-friendly way

Simplifying controls for parents

Parents shouldn't have to manage complex safety settings across dozens of different apps to keep their children safe. The Play Age Signals API simplifies this by putting age-sharing controls in one place, directly inside the Google Family Link app. Parents have a choice to share their child's age range, and if they choose to share, all Play apps that use Play Age Signals API can receive age signals. This lets children jump straight into age-appropriate content without parents having to manually configure settings inside these apps. Age ranges are never shared by default, and parents can update or turn off these settings at any time.

Centralized and easy way to manage age sharing settings for parents via Family Link App

Building on our broader safety tools

The Play Age Signals API builds upon a strong foundation of established safety features and strict policies we have long enforced on Google Play. Today, we already mandate that apps designed for families meet rigorous safety standards, and we continuously review and scan applications to ensure they are safe for children. For developers, we also offer built-in tools like Restrict Minor Access in the Play Console to help them manage who can discover their apps. For parents, Google Family Link remains a trusted, central dashboard where they can manage screen-time limits, PIN-based content filters, and app download approvals.

Expanding the Play Age Signals API globally adds a powerful new tool to our existing safety suite, helping parents and developers work together to make Google Play an even safer, more trustworthy place for families.


29 Jul 2026 1:00pm GMT

28 Jul 2026

feedAndroid Developers Blog

Celebrating 5 years of Jetpack Compose

Posted by Rebecca Franks, Developer Relations Engineer, Nick Butcher, Product Manager, Loryn Hairston, Product Marketing Manager, Android



Today, we officially celebrate five years since the release of Jetpack Compose 1.0. From version 1.0, announced on July 28th, 2021, to our latest 1.11 release, we've seen the APIs evolve significantly over the years, and we're taking a moment to celebrate.

When we officially announced the 1.0 release, we promised a simpler, faster, and more intuitive way to build native interfaces on Android. Looking back, it's safe to say that Compose didn't just deliver on that promise, but also completely changed the Android ecosystem, with more than 68% of the top 1,000 apps using it in production today.

History

Over the last five years, Compose has grown steadily. In the early days, we explored showing you how to build layouts with the basic Box, Row, and Column. Today, we've expanded Compose to work not just on mobile devices, but to other form factors such as Compose for TV, WearOS, Glance for Widgets, and even display glasses with Jetpack Compose Glimmer.



We recorded an Android Developers Backstage episode with Clara Bayarri, Engineering Lead for Jetpack, and two former leads of the team, Romain Guy and Chet Haase, along with Tor Norbye, Senior Engineering Director. In this episode, they discuss the history of Compose and the early days of development.




Compose highlights over the years

Looking back

The beginnings of Compose were very different from what you know today. Two projects were happening in parallel inside the Android team.

At the time, the Views toolkit team was thinking of unbundling the UI Toolkit into a library to help with development speed, and make it easier for developers to adopt and control updates. Meanwhile, a team was working on a novel idea to build declarative layouts by embedding XML inside Kotlin, which looked something like this:



Those two efforts merged to produce what you know today - a fully declarative UI Toolkit that utilizes the power of a compiler plugin, runtime, and Kotlin:

@Composable
fun Newsfeed(stories: List<Story>) {
    LazyColumn {
        items(stories) { story ->
            Card {
                val author = story.author
                Image(painterResource(author.profilePhoto),
                    contentDescription = author.name)
                Text(author.name)
                Text(story.content)
                if (story.hasCommentsEnabled()) {
                    for(comment in story.comments) {
                        Text(comment.mainContent)
                    }
                }
            }
        }
    }
}

And you, the community, helped us very early on! Before 2021, Compose had a pre-alpha phase, which helped ensure Compose was fit to solve the problems of our developers.

One of our favorite memories is the Android Dev Challenge. We challenged the community to build four different tasks with Compose, filling our feeds with Puppy apps, clocks, and weather apps, and giving us a ton of direct feedback that helped shape the 1.0 release.

Compose has continued to evolve, from launching with a set of Material 2 components to now supporting Material 3 Expressive.

Material 2 in Compose

Material 3 Expressive in Compose

Looking ahead

As of today, Compose 1.11 is the latest version with 1.12 coming soon, offering so much more than 1.0, 5 years ago. This year, we introduced more adaptive APIs, such as FlexBox, Grid, MediaQuery, and Styles. These APIs let you advance to the next level of premium, adaptive UI development with Compose.

At Google I/O 2026, we announced that we are now Compose-first, meaning that all future UI development will happen only in Compose, while the Views toolkit enters maintenance mode. Material Design is also shifting focus entirely to Compose, signaling an end to the findViewById era.

Community is at the heart of Compose

Over the years, you've inspired us with creative examples of how you've used Compose, and we'd love to highlight a few more examples of where we've seen exciting work. JetBrains has been a great partner for Google with Compose, expanding Compose to work across platforms with Compose Multiplatform and enabling desktop, iOS, and web developers to also enjoy the benefits of Compose.

We've really enjoyed following our most beloved newsletters from JetpackCompose.app's Dispatch, AndroidWeekly, to jetc - helping Android Developers stay up-to-date with the latest in the world of Compose and Android.

Another standout contributor is sinasamaki. They've created many delightful experiences using Compose, such as this fun ribbon modifier and the glitchy effect:


Saket Narayan has also always been an inspiration when it comes to creating useful tools for Compose, such as telephoto, a library featuring support for pan and zoom gestures and automatic sub-sampling of large images, or the latest library, Touch Robot, which allows you to easily test interaction animations:

paparazzi.gif(end = 3_000) {
  DebitCard(
    Modifier.testTag("card")
  )

  val touchRobot = rememberTouchRobot()
  LaunchedEffect(Unit) {
    touchRobot.onNode(hasTestTag("card")).performGesture {
      draw(
        path = createAndroidHeadPath(),
        duration = 3.seconds,
      )
    }
  }
}

/** A path drawing the Android head. */
fun createAndroidHeadPath(bounds: Rect): Path = TODO()

Jake Wharton, who has used Compose in innovative ways (like molecule, and even building UI with Compose for the terminal with mosaic). Chris Banes, who has built many Compose libraries over the years, with our most recent favourite - Haze for background blurring, and many of the Android Google Developer Experts like Akshay Chordiya, Huyen Tue Dao, and Katie Barnett, who've contributed to the success of Compose. But this is not about selecting individuals - there have been so many great contributors to the Compose codebase, and many of you continue to inspire us with your fun examples, libraries, and in-depth talks. Without the community, Jetpack Compose wouldn't be as successful as it is today.

Cheers to the next 5 years, and more!

Jetpack Compose has grown from an experimental idea into the standard for Android UI Development. Thank you to the entire Toolkit team at Google, and to the incredible global developer community that wrote libraries, filed bugs, and pushed the boundaries of what declarative UI can do.

This week, we'll be celebrating with some in-person birthday parties across the globe, and a live "Birthday party" on the Android Developers YouTube channel on July 30th at 13:00 UTC. During this time, we'll hang out and discuss Compose and answer your questions!

Cheers to the next 5 years, and happy composing!

28 Jul 2026 4:00pm GMT

27 Jul 2026

feedAndroid Developers Blog

How R8 made Kotlin Coroutines on Android 2x faster

Posted by Andrei Shikov, Senior Software Engineer, Android Toolkit and Jonathan Starup, Software Engineer, R8 Team






Starting from AGP 9.2.0, R8 optimizes most Atomic*FieldUpdater calls into Unsafe variants that perform 2x to 4x better on common operations. This has a particularly large impact on the kotlinx.atomicfu library that implements atomics for kotlinx.coroutines, making launching and cancelling coroutines up to 2x faster. In order to get the benefits, update your AGP to 9.2.0 or above.

With the majority of Android apps adopting Kotlin as their main language of choice, kotlinx.coroutines has become a de-facto standard for asynchronous programming. The library offers a well-designed and structured way of managing concurrent flows that is native to Kotlin. Jetpack Compose was no exception, adopting coroutines for managing pointer events, animations and other interactions. At the time of writing, most concurrent APIs in Compose call suspend functions under the hood and are launching and/or cancelling coroutines to handle updates.

As the Compose team started to investigate performance, coroutines were discovered to be a bottleneck for many operations that happen outside of composition. As an example, 80% of the time spent on creating and updating Modifier.clickable was consumed by launching and cancelling internal coroutines that handled InteractionSource updates. Based on those observations, much of early performance work was focused on removing coroutines from the default path and delaying initialization until necessary.

The cost of a coroutine

The easiest way to analyze a function's internal behavior on Android is to capture an Android Runtime (ART) method trace. An ART method trace is a tool that records the execution flow of an app, showing exactly which methods are called, their order, and how much time is spent in each, allowing developers to identify performance bottlenecks. For an empty LaunchedEffect { } call, it would look something like this:

LaunchedEffect method trace visualized in the Perfetto UI

The method trace above can be separated into three parts:

Cancelling LaunchedEffect is similar to normal completion, except it also creates a CancellationException.

From the profile above, one thing that is immediately suspicious is frequent calls into java.util.concurrent.AtomicReferenceFieldUpdater (purple or green boxes with j… labels). While each call is relatively fast, the frequency is concerning; any non-negligible overhead that is spread out across multiple invocations might add up to a noticeable regression. Zooming in on a call reveals that most of the time is spent on... reflection checks?



An up-close look at the method trace of AtomicReferenceFieldUpdater.get during LaunchedEffect initialization

Coroutines implement a lock-free tree structure for parent-child relationships that makes structured concurrency possible. Turns out, the kotlinx.atomicfu library implements lock-free atomic operations using a well-known JVM primitive, AtomicReferenceFieldUpdater. The updater uses a class reference and a field name to perform atomic operations at runtime, and it has to run several reflective safety checks to make sure the field exists and is accessible. Each operation in coroutines (starting, suspending, cancelling, completing) calls at least one atomic operation, so if it is slow, coroutines will not perform well.

Investigating AtomicReferenceFieldUpdater

But let's not get ahead of ourselves. AtomicReferenceFieldUpdater is actually well-optimized on JVM for over 10 years now, and method traces might capture overhead that is completely removed by a VM level optimization: just-in-time (JIT) or ahead-of-time (AOT) compilations. To verify performance, let's write a few benchmarks to measure the difference between atomic references from kotlinx.atomicfu and java.util.concurrent.atomic.

@RunWith(AndroidJUnit4::class)
class AtomicReferenceBenchmark {
    @get:Rule
    val benchmarkRule = BenchmarkRule()
    
    private val atomicReference = java.util.concurrent.atomic.AtomicReference(false)
    private val atomicRef = kotlinx.atomicfu.atomic<Boolean>(false)
    
    @Test
    fun atomicReference_compareAndSet() {
        benchmarkRule.measureRepeated { 
            atomicReference.compareAndSet(true, false)
            atomicReference.compareAndSet(false, true)
        }
    }

     @Test
    fun atomicRef_compareAndSet() {
        benchmarkRule.measureRepeated {
            atomicRef.compareAndSet(true, false)
            atomicRef.compareAndSet(false, true)
        }
    }

    /* measuring other methods from the method traces above */
}

Running this benchmark on a Pixel 5 (while ensuring AtomicReferenceFieldUpdater#compareAndSet is JIT compiled during warmup), yields the following results on Pixel 5 (API 33):

 50.7 ns  atomicReference_compareAndSet
135   ns  atomicRef_compareAndSet

The measurements confirm the gap, with kotlinx.atomicfu version clearly being approximately 2.7x slower. This confirms that ART does not perform any hidden optimization and reflective access checks add real overhead during runtime.

Looking back at the original method trace, the only meaningful work performed by the AtomicReferenceFieldUpdater is the internal call into Unsafe.getObjectVolatile that actually executes the underlying atomic operation. In most cases, the updater initializer is static, and can be proved to be always correct based on the structure of the surrounding class. Thus, one could statically analyze most of the AtomicReferenceFieldUpdater usages and replace them with an internal Unsafe variant during compilation. It also just happens that Android build toolchain has its very own optimizing compiler that can do exactly that.

Optimization with R8

The Atomic*FieldUpdater classes support subtle, dynamic and reflection-based use, but are often used in statically obvious patterns. This both explains the slow baseline performance and the want for optimization. R8 is a full-program optimizing compiler and is well-suited to see through the simpler patterns to skim the overhead of the reflective safety checks. R8 receives JVM bytecode after the Java or the Kotlin compiler, but to ease readability these examples are presented in Java syntax. This is why there are no type arguments for AtomicReferenceFieldUpdater.

class Example {
    volatile String data = "";
    static final AtomicReferenceFieldUpdater updater =
        AtomicReferenceFieldUpdater.newUpdater(Example.class, String.class, "data");

    void example() {
        // ...
        updater.compareAndSet(this, "", "new");
        // ...
    }
}

The base example creates a static final updater which accesses a volatile field with simple constant arguments for the holder, the type, and the name of the field. The reflection used is totally transparent. It is clear to see this updater references a valid field and that the site of the updater creation has valid access to the field.

In its essence, Atomic*FieldUpdater is a wrapper around a field offset and calls to Unsafe. The best case scenario for the optimization is to replace the updater field with an offset field and replace the updater calls with calls to Unsafe.

Optimizing Atomic*FieldUpdater

The optimization is implemented in three parts: Instrumentation, Replacement, and Clean-up.

Instrumentation

The first step is to introduce offset fields alongside the updater field in order to facilitate direct access via the Unsafe call.

static final long updater$offset =
    SyntheticUnsafe.UNSAFE.objectFieldOffset(Example.class.getDeclaredField("data"))

The field is accessed via reflection, and Unsafe is used to extract the field offset on the class. This code represents the internals of Atomic*FieldUpdater if you disregard reflection validation. Instead, the holder type of the updater and the field type of the volatile field are tracked statically in the compiler.

Note that the original field and its initialization are left as-is. The optimization process optimistically facilitates and optimizes uses and then later cleans up. This is a simple approach to the implementation but also allows partial optimization of updater fields, where some uses are left as they were while others are optimized.

Replacement

At this point in the compiler, after a suitable concurrency join point, we have a list of instrumented updater fields. This means that we can optimize each call site individually based on a few conditions. Consider an example call:

updater.compareAndSet(holder, expectedValue, newValue);

The conditions that Atomic*FieldUpdater requires are these:

If all conditions are met, then the call is replaced by a call to Unsafe without any of the reflection checks.

SyntheticUnsafe.UNSAFE.compareAndSwapObject(holder, Example.updater$offset, expectedValue, newValue)

This new call is faster and simpler but it differs from the original call in regards to its handling of null values in updater and holder. Unless statically ruled out, null-checks are inserted for both.

Clean-up

At this point, the holding class has the original updater field and the new offset field along with call sites that might use either one of the two. If none of the call sites were optimized, then the offset field should be removed and if all of the call sites were optimized, then the updater field should be removed. In both cases the initializing call should also be deleted. The deletion of unused fields and removal of dead code is already done in the compiler, but removing the initializing code here requires a few more tricks.

Both the call to newUpdater and getDeclaredField might have side effects as they can throw exceptions (and their implementation is also unknown since it depends on the API version). This means that by generic optimization, they cannot safely be removed. So this clean-up required explicit consideration of the instrumented fields, since those are statically known to be free of exceptions.

In the end, the simple updater example shown above looks like this after optimization:

class Example {
    volatile String data = "";
    static final long updater$offset =
        SyntheticUnsafe.UNSAFE.objectFieldOffset(Example.class.getDeclaredField("data"))

    void example() {
        // ...
        SyntheticUnsafe.UNSAFE.compareAndSwapObject(this, Example.updater$offset, "", "new")
        // ...
    }
}

Results

After these optimizations, kotlinx.atomicfu and most explicit uses of AtomicInt/Long/ReferenceFieldUpdater now match AtomicReference performance with R8 applied. In fact, it is even faster in some benchmarks; kotlinx.atomicfu has a compiler plugin that can inline atomic instances into fields, reducing allocations required to create an atomically updated field.

Jetpack Compose was the main beneficiary of this work. Compose runtime has a number of microbenchmarks that track coroutine performance very closely to catch performance regressions early. When the benchmarks were updated to a new version of R8, we noticed a 2x improvement when launching and cancelling coroutines in LaunchedEffect!



Benchmark graph illustrating the time taken when starting and cancelling coroutines in LaunchedEffect (lower is better). The change in the graph corresponds to an R8 update, showcasing 2x improvement.

Aside from that, the ART team is implementing these optimizations natively at the VM level. If your app is targeting API 37 and is running on a recent version of Android, it is possible that your device is already optimizing coroutines in a similar way. The coroutine benchmarks above observed ~15% improvement in performance after JIT updates in the recent versions of ART.

Your app will receive this optimization by default when upgrading to AGP 9.2.0 or by using R8 9.2.0 directly. For more information, see D8 dexer and R8 shrinker.

27 Jul 2026 1:00pm GMT

22 Jul 2026

feedAndroid Developers Blog

Optimize your apps for the next generation of Samsung Galaxy devices

Posted by Fahd Imtiaz, Senior Product Manager and Miguel Montemayor, Developer Relations Engineer, Android Developer Experience



Today at Galaxy Unpacked, Samsung unveiled its latest lineup of foldable and wearable devices. For developers, this means that the variety of form factors, screen sizes, and device postures your app needs to support is expanding once again.

With devices like the Galaxy Z Fold8, the ecosystem is expanding to include hardware with a landscape-first natural orientation and a wider aspect ratio in its main display state. Whether a user is unfolding a large display, flipping open a cover screen, or glancing at their wrist, users expect a flawless experience. To help you meet this moment, we're sharing actionable guidance and new tooling updates to enable you to build adaptively proactively.

Rethink layout architecture for dynamic displays, including ultra-wide foldables

Building for the latest foldables means dropping assumptions about display orientation and size. This is especially true for the Galaxy Z Fold8, which adopts an ultra-wide display, adding to the variety of aspect ratios to account for. Devices with this landscape-first natural orientation show the limitations of hardcoded layout rules when users unfold the device. That's why we've introduced dedicated guidance for building for landscape foldables and trifolds.


To build a responsive UI that handles these physics seamlessly, focus on the following core pillars:

  • Build fluid, adaptive layouts: Wide aspect ratios and compact vertical heights require fluid UIs that scale responsively. Our updated adaptive design guidance advises considering the window class width first to determine layout changes, then adjusting for height. To let individual components fluidly adapt to the grid, structure your layout using flexible containers that allow your content to automatically wrap, span, and reflow. For design inspiration browse our adaptive sample app and dual-screen design galleries.
  • Track actual app space: Your app's display space rarely matches the physical device size, especially on an ultra-wide screen during multi-window, split-screen, or multitasking states. Sometimes even the orientations differ. Leverage Window Size Classes using the Jetpack Window Manager library to calculate the exact space your app occupies.


  • Leverage the latest Jetpack Compose Update: Start by adopting the stable Jetpack Compose April '26 release (Compose BOM version 2026.04.01).Take advantage of the new structural layout tools to manage complex architectures. The new Grid API allows you to define dynamic tracks and column spans without the performance overhead of a lazy list. Pair Grid with the new FlexBox layout API to easily handle multi-axis alignment and dynamic item wrapping. You can also use the new MediaQuery API to adapt your UI to its environment, using conditions to detect signals like device posture, window size, and keyboard types.
  • Make your app fold aware: Use the Jetpack WindowManager library, which provides an API surface for foldable device window features such as folds and hinges. When your app is fold aware, it can adapt its layout to avoid placing important content in the area of folds or hinges and use folds and hinges as natural separators.
  • Maintain app continuity: Avoid breaking the user journey when the device configuration shifts. Retain your UI state using ViewModel to ensure smooth transitions when a user folds or unfolds their device.

Ensure seamless camera capture on foldable devices

Camera implementation on foldables brings unique hardware quirks. Moving from a compact outer display to an expanded inner display introduces distinct layout aspect ratios while device rotation remains unchanged. If an app assumes a fixed portrait relationship between the camera sensor and the device layout, the app will likely suffer from sideways, stretched, or cropped previews during these folding transitions.
When optimizing your app's media pipeline, migrate your capture experiences to CameraX using the CameraX migration skill. The library's PreviewView automatically handles sensor orientation, device rotation, and scaling behind the scenes. This guarantees a clean, stable preview regardless of how the user holds or positions the device. If you are maintaining an existing Camera2 codebase, integrate the CameraViewfinder library to apply these complex aspect ratio and rotation transformations automatically without needing a total architecture overhaul.

Extend glanceable interactions to Wear OS 7

The opportunity to build for this new generation of devices extends right to the wrist. Launching with Wear OS 7, Wear Widgets give you a fresh surface to provide users with instant, glanceable access to their essential updates. You can build these highly expressive experiences using Jetpack Glance and RemoteCompose. Crucially, Widgets built with this framework can now populate multi-widget tiles that were previously reserved for first-party widgets.

Build intelligent features

Gemini intelligence already completes tasks on users' behalf, and you can experiment with the intelligence system by sharing your apps capabilities.

Samsung's new foldable devices come with Gemini Nano 4, our latest on-device model. Nano 4 provides support for over 140 languages, better multimodal understanding, and much more. Use ML Kit's Prompt API with advanced features like structured output and thinking mode to build intelligent features on-device.

Start optimizing today

The tools and frameworks are ready to help you optimize your app for all screen sizes. Begin by exploring our guidance for building adaptive apps to learn more about core adaptive design principles.

To dive deeper, check out our comprehensive YouTube playlist. Finally, ensure your app delivers a flawless, premium experience on the newest form factors by reviewing our dedicated quality guidelines for trifolds and landscape foldables and WearOS.

Unfold the future today!

22 Jul 2026 7:00pm GMT