Skip to content

Android 17 Resizability: How to Test Your App Adapts

Every post about Android 17's resizability mandate tells you what breaks. Almost none tell you how to know you've fixed it, which is a harder problem, because your entire UI test suite runs at exactly one window size.

Share
Modular blocks held between two brackets, with faint outlines of the same arrangement at several widths behind it and some blocks breaking loose

There are plenty of posts explaining what Android 17 breaks. The large-screen opt-out is gone, screenOrientation is ignored, portrait-locked apps will render at tablet width, and there's a Play deadline attached. All true, all well covered.

Far fewer address the harder question: how do you know you've fixed it?

That's a testing problem, not a layout problem, and it's a nastier one than it looks, because your entire UI test suite currently runs at exactly one window size. Every test you have passes at the size it was written for. None of them can tell you what happens when a user drags your app into a third of a split screen.

In this post:

What Actually Changed, Briefly

Android 17 (API level 37) shipped stable on 16 June 2026. For apps targeting API 37, orientation, resizability and aspect-ratio restrictions no longer apply on displays whose smallest width is greater than 600dp.

The system ignores the legacy escape hatches: the screenOrientation manifest attribute, runtime calls to setRequestedOrientation(), resizeableActivity="false", and the minAspectRatio / maxAspectRatio constraints. Games are exempt, based on their app category in Google Play.

Two details worth pinning down, because both get misreported:

The trigger is your targetSdk, not the user's OS version. An app running on an Android 17 device that still targets API 36 keeps the old behaviour. Android 16 shipped a temporary opt-out, and it still works until you raise your target.

Users can opt back in. Google's guidance notes that users retain control through the aspect ratio settings, where they can explicitly choose the app's requested behaviour. So you need to support the full range of aspect ratios users can select, including resizable windows. The constraint isn't "support one alternative layout," it's "support the range."

On timing: Google's February post stated that, for Google Play, new apps and updates must target API level 37, making this behaviour mandatory for distribution in August 2027. Check the Play Console for the deadline that applies to your app, since the target-API policy has shifted before.

Why Your Test Suite Can't See This

Here's the uncomfortable structural point.

Instrumented UI tests run on a device or emulator, in a window, at whatever size that device provides. Your test suite has one window size baked into it: the emulator profile in your CI config. Every assertion in every test has only ever been evaluated against that one geometry.

That means your suite has a specific and total blind spot: it cannot fail because of a layout that breaks at a different size. Not "it might miss it." It structurally cannot observe it. A portrait-locked app that shatters at 1280dp will have a completely green CI run, because nothing in the pipeline has ever rendered it at 1280dp.

The usual response is to open the resizable emulator in Android Studio and drag the window around. That's a genuinely useful thing to do, and you should do it. But be clear about what it is: a spot check, performed once, by one person, on one build. It doesn't protect you next sprint when someone adds a fixed-width container to a shared component.

The gap between "we checked it" and "we test it" is the entire problem here. A mandate with a 2027 deadline is not a one-off fix. It's a property your app has to keep having, through every refactor between now and then. Properties you don't test are properties you lose.

The Bug Class Everyone Misses: It's Not Visual

Most coverage frames this as an appearance problem: stretched layouts, off-screen components, buttons you can't reach. Google's own behaviour-change documentation warns about exactly that, flagging stretched layouts and off-screen animations and components, particularly for elements designed for small layouts locked in portrait.

Those are real, and they're the easy half. They're visible, and a screenshot test catches them.

The harder half is state. Resizing a window is a configuration change, and a configuration change destroys and recreates your activity. Rotate a device, drag a window edge, unfold a phone, move to a connected display, and each one tears down and rebuilds. Anything held in a place that doesn't survive that is simply gone.

If your app has been portrait-locked, this code path has effectively never run in production. You have, in all likelihood, never had a user rotate the app. So every place you kept state somewhere fragile has been sitting there, unexercised and undiscovered, since the day it was written.

What that looks like in practice: a half-completed form that clears when a tablet user snaps the window, a scroll position that jumps to the top, a dialogue that vanishes mid-flow, a partially-entered payment field that resets. None of these is visual bugs. None of them shows up in a screenshot diff. All of them are worse for the user than a stretched layout, because the user loses work rather than merely seeing something ugly.

This is the part I'd test first, and it's the part almost nobody mentions.

Testing Before You Commit to targetSdk 37

You don't have to raise your target to start finding these. Google documents two ways to do this:

targetSdkPreview. Set targetSdkPreview = "CinnamonBun" on a branch and run against Android 17 with the Pixel Tablet and Pixel Fold emulators in Android Studio. This gets you the real behaviour without shipping the target bump.

The app compatibility framework. If you're not yet on API 36, enable the UNIVERSAL_RESIZABLE_BY_DEFAULT flag to turn on the specific change in isolation.

The sequencing that follows from this is worth stating plainly, because the tempting order is wrong. Don't raise targetSdk and ship. Raise compileSdk first, so you get deprecation warnings without opting into behaviour changes. Then, on a branch, raise the target and run against a large-screen emulator in landscape and in a resizable window. That single run surfaces most of it.

Google also points to Compose UI Check, which audits your UI automatically and suggests adaptivity improvements. Treat it the way you'd treat a linter: excellent at finding the mechanical problems, silent about the ones that matter most.

Building the Actual Test Matrix

The API that makes this tractable is DeviceConfigurationOverride, available in Compose 1.7 and higher. It simulates device configuration locally for whatever composable you're testing, so you can test multiple arbitrary UI sizes in a single run of your suite on a single device or emulator.

The one you want is ForcedSize, which fits any layout into the available space regardless of the device's real geometry. From Google's documentation:

DeviceConfigurationOverride(
    DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
    MyScreen()
    // Will be rendered in the space for 1280dp by 800dp without clipping.
}

That's the whole trick. You can run your tablet layout tests on a small phone emulator. No new CI hardware, no device farm, no separate pipeline, just the same test suite parameterised across sizes.

The other overrides in the same family are worth knowing, since they compose with .then(): LayoutDirection for RTL, Locales, RoundScreen, and font-scale overrides. Testing several configuration parameters at once (size, font size, locale, theme) in a single test is exactly the sort of combinatorial coverage that's otherwise impossible.

Which sizes to pick. Use the window size class breakpoints rather than inventing your own. Google recommends testing layout behaviour across all window sizes, especially at the compact, medium, and expanded breakpoint widths. Those are the boundaries where your layout logic actually branches, so they're where bugs live. Testing at 800dp and 810dp tells you nothing. Testing either side of a breakpoint tells you everything.

Add screenshot tests for the visual half. Host-side screenshot testing is fast and scalable for verifying appearance across display sizes, and @PreviewScreenSizes gives you the same coverage in previews. Screenshots handle "does it look wrong." They don't handle "did the user lose their data," which is why they're the second thing to set up, not the first.

What to Assert (and What Not To)

The instinct is to assert that things look right. Resist it, because it produces brittle tests and misses the important failures.

Better assertions, roughly in order of value:

Every interactive element is reachable. Not visible, but reachable. Google's guidance on layouts specifically flags that if layouts don't scroll, users might not be able to access buttons or other elements that are off-screen in landscape. The test isn't "is the submit button displayed." It's "can I get to the submit button from here." A performScrollTo() before your click assertion is the difference between a test that catches this and one that doesn't.

State survives recreation. This is the one. Compose's testing docs document StateRestorationTester with emulateSavedInstanceStateRestore() for exactly this: set your content, perform actions that modify state, trigger a recreation, then verify the state came back. If you write one new category of test in response to Android 17, make it this one, because it targets the failure that costs users work rather than aesthetics.

Nothing measures the screen. Grep for anything reading display metrics to make layout decisions. Google's own guidance is blunt in the camera case: screen size should not determine viewfinder dimensions. Use window metrics instead, or you risk a stretched preview. The general principle is broader than cameras. Your app's window is not the device's screen. In split screen it's a fraction of it, in desktop windowing it's arbitrary and user-controlled, and on a connected display it's something else again. Any code that conflates the two is a bug that hasn't fired yet.

Don't assert exact pixel positions or fixed dimensions. Those tests will fail on the next breakpoint change and teach your team to ignore failures.

My Take

Portrait lock was never really a design decision. It was a testing decision.

That's the part I think everyone leaves out. Locking orientation halved the test matrix. It meant configuration changes never happened, activity recreation never fired, state restoration never got exercised, and the layout only ever had to work at one aspect ratio. For a lot of teams, it was the single highest-leverage way to reduce the surface area of what had to be verified, and it was free because the platform let you declare it in one line of the manifest.

Android 17 isn't taking away a layout option. It's calling in the test debt that shortcut accumulated. Which is why "how do I fix my layout" is the wrong first question. The layout is a day's work; the missing test coverage for configuration changes is the real project.

Having watched iOS go through this, the teams that suffered were the ones that treated it as visual. iPad multitasking landed with size classes in 2015, and the apps that had a bad time weren't the ones with stretched layouts, since those got fixed in a sprint and everyone moved on. The ones that took months were the apps where state lived in places that assumed the view controller was never coming back. Same shape of problem, same decade-long tail. Android now has the advantage of arriving late enough to have StateRestorationTester and DeviceConfigurationOverride ready to hand, which iOS teams did not.

The August 2027 date is generous enough to be dangerous. A year of runway is long enough for this to drop off the roadmap, and short enough that it'll be a crisis when it returns. The sensible move isn't to schedule "the Android 17 migration" for Q2 next year. It's to add size-parameterised tests to your suite now, on your current targetSdk, and let them go red. You'll find out today what's broken, at the pace of one bug per sprint, instead of finding out all of it at once in eighteen months.

And the user-facing version, since that's what actually settles it: nobody has ever cared what your manifest declares. They care that dragging your app into a split screen doesn't lose the message they were typing. That's the test to write first, because it's the failure they'd tell other people about.

FAQ

Does Android 17 break my app if I don't change my targetSdk?
No. The behaviour applies to apps targeting API level 37 or higher. On an Android 17 device, an app still targeting API 36 keeps the previous behaviour, including the Android 16 opt-out.

What exactly stops working at targetSdk 37?
On displays with smallest width greater than 600dp, the system ignores screenOrientation, setRequestedOrientation(), resizeableActivity="false", and minAspectRatio / maxAspectRatio.

Are games affected?
Games are exempt; eligibility is determined by the app category in Google Play.

Can I test this without raising targetSdk?
Yes. Use targetSdkPreview = "CinnamonBun" on a branch, or enable the UNIVERSAL_RESIZABLE_BY_DEFAULT flag via the app compatibility framework if you don't yet target API 36.

How do I test multiple window sizes without multiple emulators?
DeviceConfigurationOverride.ForcedSize() renders a composable at an arbitrary size regardless of the device running the test, so a single small emulator can exercise tablet and desktop layouts.

When is the Play deadline?
Google's February post said August 2027 is when new apps and updates must target API level 37. Confirm against the Play Console for your specific app.