A few weeks ago I wrote about the Android 17 behavior changes that'll actually bite you — the quiet SDK-gated breaks around config restarts, background audio, and large-screen adaptivity. That post was the defensive read. This one is the other side: the new APIs in API level 37 that exist because Google added genuinely useful capabilities, not to enforce policy.
Android 17 shipped on June 16, 2026. The headline coverage predictably went to the consumer features. But there are half a dozen new developer APIs in this release that are worth understanding properly — one of them is the most interesting cross-device primitive Android has shipped in years, one gives you free performance you get by doing nothing, and one finally closes a contact-access privacy gap that's bothered me since the READ_CONTACTS permission was the only path forward.
1. The Handoff API — Cross-Device Continuity, Finally Done at the Platform Level
This is the one that actually surprised me. Android 17 ships a new Handoff API that lets you specify activity state to be resumed on a nearby Android device. Start reading an article on your phone, pick it up on your tablet. The system handles synchronization via CompanionDeviceManager and surfaces a handoff suggestion in the launcher on the nearby device. No cloud sync setup, no deep-linking gymnastics you have to build yourself — it's a platform primitive.
The implementation is per-activity. You opt in by calling setHandoffEnabled(), then implement a callback that returns the state the system should hand off:
// Enable Handoff for this activity
override fun onResume() {
super.onResume()
setHandoffEnabled(true, HandoffActivityParams())
}
// Provide the state when the system asks for it
override fun onHandoffActivityDataRequested(
requestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val bundle = Bundle().apply {
putString("article_id", currentArticleId)
putInt("scroll_position", binding.recycler.computeVerticalScrollOffset())
}
return HandoffActivityData.Builder()
.setData(bundle)
.build()
}
On the receiving device, the system launches your app and delivers the bundle through standard Activity extras, so restoring state is the same pattern you already use for process death. If your app isn't installed on the receiving device, the API also supports an app-to-web fallback — you can specify a URL and the system opens it in the browser instead of dropping the handoff entirely.
What the system does on the other end
When the system detects a nearby paired device (via CompanionDeviceManager), it displays a floating suggestion in that device's launcher or taskbar. The user taps it, your app launches, and the bundle you returned lands as extras on the incoming Intent. The whole flow is asynchronous — your onHandoffActivityDataRequested() callback fires right before the suggestion is surfaced, so you get a fresh snapshot of state, not whatever was current when you first called setHandoffEnabled().
Launch scope: At launch, Handoff supports mobile-to-tablet transitions on Android 17 devices. Broader device support is planned for later in 2026. It won't reach users broadly until API 37 adoption grows, but this is the time to build the integration — the API is stable, not experimental.
For Nodat, this is immediately interesting. A note opened on your phone showing up as a handoff suggestion on your nearby tablet — that's a real use case, not a contrived demo. The implementation effort is low: add the callback, serialize the relevant state, restore it on launch. The hard part of cross-device continuity (detecting proximity, surfacing the UI, managing the session) is handled by the platform.
2. Free Performance — ART GC and Lock-Free MessageQueue
Two performance improvements in Android 17 require zero code changes on your part. Both apply to apps targeting API level 37.
ART garbage collector changes: Android 17 introduces more frequent, lower-cost young-generation collections by separating short-lived objects from stable ones. The practical effect is reduced CPU usage, lower power draw, and less UI jitter from GC pauses. This has been a long-standing source of micro-stutter in apps with high allocation rates — anything animating custom views, building large RecyclerView item types, or running tight loops over collections. You don't opt in, it's automatic once you target API 37.
Lock-free MessageQueue: Apps targeting SDK 37 or higher get a lock-free architecture for android.os.MessageQueue. The old synchronized queue could block briefly when handlers posted messages from multiple threads, contributing to dropped frames during periods of high handler traffic. The lock-free version removes that contention point. Google's own benchmarks show a measurable reduction in missed frames for apps with active background thread communication — navigation apps, apps with live data pipelines, anything pumping data from a background service to the UI thread.
If you run a Macrobenchmark suite (I'd argue you should — see my startup time post for setup), both of these are worth a fresh baseline run after bumping target SDK to 37. The gains are real but vary by app profile. Measure before claiming wins.
For apps like Samachar — where the news feed is fed by a background network layer posting events to the main thread — the MessageQueue change is the more interesting one. Apps with that architecture have always had an invisible cost at high message frequency. The lock-free queue removes it.
3. Contact Picker — Privacy-Preserving Contacts Without READ_CONTACTS
The READ_CONTACTS permission is one of those permissions users have learned to be suspicious of, correctly. Most apps that ask for it only need one thing: let the user pick a contact and grab a phone number or email. The full permission grants access to the entire contacts database, which is wildly more than that use case requires.
Android 17 introduces a standardized Contact Picker (API level 37+) that flips the model. Instead of requesting a blanket permission, your app specifies which fields it needs, the system presents a browsable picker, the user selects exactly which contact and which data to share, and your app receives read-only access to that selected data only. No permission dialog, no broad database access, no explaining to a suspicious user why you need their entire address book.
// Declare what fields you need
val request = ContactPickerRequest(
fields = listOf(
ContactPickerRequest.FIELD_PHONE_NUMBER,
ContactPickerRequest.FIELD_EMAIL_ADDRESS
)
)
// Launch the picker
val launcher = registerForActivityResult(
ActivityResultContracts.PickContact(request)
) { result: ContactPickerResult? ->
result?.let {
val phone = it.getPhoneNumber()
val email = it.getEmailAddress()
// use the contact data
}
}
launcher.launch(null)
The picker supports search, profile switching, and multi-selection. It's a system-provided UI so it looks consistent across devices and doesn't require you to build or maintain contact browsing UI yourself.
This matters practically for store placement, not just user trust. Google Play's data safety section requires you to declare contact data access, and a broad permission you're using for a narrow purpose creates friction in review. Narrow access via the picker is genuinely cleaner on both axes.
4. Live Updates Semantic Colors — Notification UX That Actually Communicates
Android 15 introduced Live Updates (persistent ongoing notifications that display real-time progress). Android 17 adds a semantic color API on top of them: your notification content can now carry explicit meaning through color rather than relying on the user to read the text.
The system defines four semantic styles — safe (green), caution (orange), danger (red), and info (blue) — applied as spans on notification text:
val ssb = SpannableStringBuilder()
.append("Delivery: ")
.append(
"OUT FOR DELIVERY",
Notification.createSemanticStyleAnnotation(
Notification.SEMANTIC_STYLE_SAFE
),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
.append(" — arrives in 12 min")
val notification = Notification.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_delivery)
.setContentTitle("Your order")
.setContentText(ssb)
.setOngoing(true)
.setRequestPromotedOngoing(true)
.build()
The styling applies to Notification, Notification.Metric, Notification.ProgressStyle.Point, and Notification.ProgressStyle.Segment. The system maps your semantic intent to the appropriate visual style for the user's theme and accessibility settings — you don't hardcode colors, you declare meaning.
For apps that surface status updates in persistent notifications — delivery tracking, ride hailing, background media, live workout tracking — this is a clean upgrade to the signal-to-noise ratio in the notification shade.
5. PQC APK Signing — Future-Proofing Before the Quantum Deadline Matters
Android 17 adds support for post-quantum cryptography (PQC) APK signing via a hybrid scheme that combines your existing classical key (RSA or EC) with an ML-DSA (Module-Lattice-Based Digital Signature Algorithm) key. The hybrid approach is fully backward compatible — devices that don't understand ML-DSA fall back to the classical signature, so you can start issuing PQC-hybrid APKs now without breaking anything.
The reason to care: quantum computers capable of breaking current RSA/EC signatures aren't a theoretical concern anymore, and signing key compromise requires rotating identity — something you want to do on your schedule, not in response to an incident. The earlier you establish a PQC hybrid identity, the more signing history gets covered.
There are two paths depending on how you manage signing keys:
- Play App Signing users (most indie developers): wait for Google Play to enable a PQC upgrade option in the Console. You can't self-service this yet, but you don't need to — Play App Signing means Google manages the key, and they'll upgrade when the tooling is ready.
- Self-managed keys: use the updated
apksignerto rotate to a hybrid identity. One constraint: you must create a new classical key as part of the rotation; you cannot add ML-DSA to an existing key.
No urgency right now, but don't ignore it: PQC signing is a good thing to track in your Q3/Q4 planning rather than your immediate backlog. The window to act proactively is several years, not months — but establishing awareness now means you won't be scrambling when timeline pressure actually materializes.
6. Two Smaller APIs Worth Bookmarking
JobScheduler.getPendingJobReasonStats()
New in API 37: JobScheduler.getPendingJobReasonStats() returns a map of pending job reasons and the cumulative duration each reason has been blocking your jobs. If a job isn't running and you don't know why — charging constraint, network constraint, system throttling — this method tells you exactly what's blocking it and for how long. Turns a previously opaque debugging process into one call.
Camera RAW14
Professional camera apps can now capture 14-bit per pixel RAW images via the new ImageFormat.RAW14 constant. More color depth, less banding in shadows and highlights. Irrelevant for most apps, essential for the narrow set of apps where sensor fidelity is the product.
What I'm Actually Shipping
The Handoff API is the one I'm prototyping first. The use case for Nodat — picking up a note on a second device without any cloud sync infrastructure — is exactly what it's designed for, and the implementation is lightweight enough that I can have a working prototype in an afternoon. I'll also add the Contact Picker to any app that currently uses READ_CONTACTS for a share-by-contact flow. The permission is a user trust cost that now has a cleaner solution.
The ART GC and MessageQueue improvements are automatic — they take effect when I bump targetSdkVersion to 37, which needs to happen before Android 17 becomes the target SDK enforcement threshold anyway. I'll run the Macrobenchmark suite after bumping and see what the numbers look like in practice.
PQC signing goes in the backlog with a note to revisit when Google enables the Play App Signing upgrade path in the Console. No action needed yet, but the wrong move is to forget about it entirely and catch it late.
The pattern across all of this: Android 17 isn't a one-dimensional "things that break" release. The breakage is real — I covered it in the behavior changes post — but so are the new capabilities. The Handoff API in particular is something the platform couldn't offer a year ago. Worth paying attention to what's newly possible, not just what's newly broken.
No comments yet. Be the first to leave one!