DEV Community

Cover image for Adaptable apps on ChromeOS: a post-mortem
Thomas Künneth
Thomas Künneth

Posted on

Adaptable apps on ChromeOS: a post-mortem

In my previous article Building a custom launcher for ChromeOS I described how Be nice runs on Chromebooks: not as a real default home app, because default home settings (Settings.ACTION_HOME_SETTINGS) usually are not available on ChromeOS, but as a normal Android app in an ARC window. I pretended the app is the launcher in code (detectIsHomeApp() returns true on ChromeOS), worked around split-screen bugs that leave the app a black rectangle, and gave up transparent wallpaper for an opaque scaffold because ARC does not show the ChromeOS desktop behind the window the way a phone shows its wallpaper.

What that article obviously could not cover is the fight that came right after. For about a week in May 2026 I tried to get rid of a system confirmation ChromeOS shows when users open the preset-size menu in the ARC window title bar and choose Resizable, at least on Play Store builds. During my experiments, manifest changes often looked fine from Android Studio; however, on Play, the dialog stayed. I tried adding XML, asking AI assistants, including Google’s own models, for the magic flag. Here’s what I learned along the way.

What users see

ChromeOS does not present Play Store Android apps the same way in every posture. On a convertible or clamshell Chromebook in laptop use, ARC usually places apps in individual windows (chromeos.dev). The title bar often labels the current layout (Phone, Tablet, or Resizable) and opens a menu to switch presets; choosing Resizable is what triggers the warning below, not dragging the window frame by itself (in fact, resizing the window by dragging one of the window edges does not work until it is allowed through the dialog). In tablet mode the picture is different: apps commonly launch and stay full screen, which matches how ChromeOS has long treated touch-first use on detachables (Chrome Unboxed on immersive mode). The resize presets and the warning below matter most when you are in a windowed, laptop-style layout, not when an app is already filling the screen in tablet mode.

From that menu, when you choose Resizable in a windowed, laptop-style layout, ChromeOS brings up a confirmation that has been written about since around 2021 (Chrome Unboxed, Chrome Nerd):

This app is designed for mobile and may not resize well. The app may experience issues or restart.

Some apps never offer Tablet or Resizable at all; they stay on Phone with “This app only supports this size”, which is the stricter case when developers set resizeableActivity="false" (About Chromebooks). Be nice was not locked like that; Tablet and Resizable appeared in the title-bar menu, but the mobile warning still appeared when I chose Resizable on Play installs.

What made debugging miserable was Studio versus Play. Local installs felt better; store builds did not. Play Help describes Phone, Tablet, and Resizable presets accessible directly from the window title bar, which matches how I used them on my Chromebook, though the exact entry point may differ by ChromeOS version. Play Help also says resize presets apply to newly downloaded apps, so I shipped many builds in quick succession. Fortunately there is an internal testing track. Never do this in production.

What I started with

The manifest did not spell out ChromeOS windowing. There was no explicit resizeableActivity, no ChromeOS window metadata, and no optional touchscreen or PC hardware features. On ordinary Android that omission was deliberate: for apps targeting API level 24 and higher, resizeableActivity defaults to "true" when you leave it out (<application>, <activity>). Be nice targets API 37 with minSdk 28, so phone and tablet builds were already resizable in multi-window terms; I had never needed the attribute in XML. What I lacked were the Chromebook-specific hints, not the baseline Android flag. The launcher already listened for size-related configChanges, including smallestScreenSize, but I had not told ChromeOS how I wanted freeform launch or Play classification on devices without touch. The working theory was simple: add the flags Google documents for Chromebooks, and the dialog would go away.

What I tried

Declare the app resizable. I set android:resizeableActivity="true" on the application and told Play users I had “improved detection of the app's resize capabilities on ChromeOS.” On Android I had mostly made explicit what the target SDK already implied; it did not unlock resize on phones or tablets that was missing before. It does not remove the “designed for mobile” prompt when someone picks Resizable on ChromeOS either. I had conflated “allowed to resize” with “ChromeOS will not warn.”

Tell the system I support size changes. I added android.supports_size_changes at the application level, later duplicated it on individual activities, and at one point switched from <meta-data> to <property>. The hope was that ChromeOS would treat the app as resize-aware and skip the warning. Nothing in the public docs ties that flag to suppressing the dialog; the warning outlived every variant.

Ask for a tablet-shaped launch. I set WindowManagerPreference:FreeformWindowSize to tablet on the home activity so the window would open in a tablet preset rather than phone-sized mobile. Changelog copy spoke of “default tablet window size.” That metadata only affects how the window opens in freeform mode (chromeos.dev), not whether the user sees the mobile warning when they switch to Resizable. I later removed the tablet preset while still chasing the same popup, so I had already abandoned my own hypothesis.

Pin static launch bounds. I added <layout> on the launcher (and eventually on other activities) with default width and height in dp; I tried 840×640 first, then larger bounds as the experiment went on. At the same time I still had, or had just had, tablet freeform metadata on the same activity. Documentation warns that static <layout> bounds and FreeformWindowSize can conflict; I ran both anyway. Without success, that is.

Declare Chromebook-friendly hardware. Following a suggestion from Gemini, I marked touchscreen, faketouch, and android.hardware.type.pc as not required, and added <supports-screens> with every size bucket enabled. The touchscreen and PC entries are appropriate for Play on Chromebooks (manifest compatibility), but they address installability and input, not the resize confirmation string.

Widen configChanges to avoid restarts. I started with a modest list, then expanded it, then trimmed it back down. At one point the manifest listed almost every flag I could find, including locale, font scale, and color mode, on the theory that activity restarts on resize triggered bad behavior or the warning. It became unreadable, and it did not help.

Activity embedding override. I even added PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE at the application level. That belongs to a different feature (embedding / multi-pane); it has no documented link to ChromeOS freeform resize warnings, and, to no one's surprise, it did not help.

Time to recap

Declaring resizeableActivity tells the system the app accepts window resize (rather than staying in a fixed compatibility viewport on large screens); it does not opt out of the Resizable confirmation. supports_size_changes and launch metadata do not either. Optional touchscreen declarations matter for Chromebook distribution; they were never documented as silencing “designed for mobile.” The dialog fits Google’s preset-size UX, which is a way for users to pick Phone or Tablet without every app being fully adaptive (Android Community). I had spent a week tuning manifest knobs for a message the OS shows on purpose when the user chooses Resizable, and for which I have not found an officially documented, bulletproof way out.

The biggest learning was not to underestimate what changes when the app comes from a Play install. Installing from Android Studio had led me to think the problem was solved; the store build told a different story. Play distribution, install context, and ChromeOS window presets are part of the behavior you are debugging, and they are not fully visible if you only deploy from the IDE.

Nothing in this effort demonstrated that the “designed for mobile” dialog can be removed from the manifest alone. I continue with a manifest that reflects adaptability on Android in general: resizeableActivity on the application, android.supports_size_changes on the home activity, optional touchscreen / type.pc hardware declarations for desktop-class devices, and size-related configChanges as chromeos.dev's second option for window reshape. The adaptive UI itself stays in Compose (WindowSizeClass and layouts that follow the window).

That is the story in prose; here is what it looks like in app/src/main/AndroidManifest.xml today:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <queries>
        <intent>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent>
    </queries>

    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.faketouch"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.type.pc"
        android:required="false" />

    <application
        android:name=".BeNiceApplication"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:enableOnBackInvokedCallback="true"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:resizeableActivity="true"
        android:supportsRtl="true"
        android:theme="@style/Theme.BeNice"
        tools:ignore="UnusedAttribute">

        <activity
            android:name=".AppChooserActivity"
            android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
            android:exported="true"
            android:launchMode="singleTask"
            android:stateNotNeeded="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
                android:name="android.supports_size_changes"
                android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <activity
            android:name=".ImageViewerActivity"
            android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.QUICK_VIEW" />
            </intent-filter>
        </activity>

        <activity
            android:name=".BeNiceActivity"
            android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
            android:excludeFromRecents="true"
            android:exported="true">
            <intent-filter>
                <action android:name="de.thomaskuenneth.benice.intent.action.ACTION_LAUNCH_APP" />
            </intent-filter>
            <intent-filter>
                <action android:name="de.thomaskuenneth.benice.intent.action.ACTION_LAUNCH_APP_PAIR" />
            </intent-filter>
        </activity>

        <service
            android:name=".BeNiceTileService"
            android:exported="true"
            android:icon="@drawable/tile_service_icon"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
            <intent-filter>
                <action android:name="android.service.quicksettings.action.QS_TILE" />
            </intent-filter>
        </service>

        <receiver
            android:name=".ShortcutPinnedReceiver"
            android:exported="false" />

    </application>

</manifest>
Enter fullscreen mode Exit fullscreen mode

If you strip away the experiments, two resize declarations and one documented fallback are still worth keeping, and none of them is the magic flag that silences the dialog:

  • android:resizeableActivity="true" on <application>. Google expects apps that behave well when resized to declare resizeableActivity or supports_size_changes as enabled (device compatibility mode). At my target SDK the default is already true; I keep it explicit anyway.

  • <meta-data android:name="android.supports_size_changes" android:value="true" /> on AppChooserActivity. Same guidance: declare that the activity handles size changes without fighting compatibility mode. I put it on the home activity, not on every screen.

  • android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize" on activities. chromeos.dev lists this as its second option for resize; the first is ViewModel plus saved state so activity recreation stays cheap. I use the flags to skip a full tear-down when the ARC window changes shape. Current adaptive app guidance puts currentWindowAdaptiveInfo() and responsive Compose layouts first; I do not override onConfigurationChanged, and I am not claiming this manifest line is the adaptability strategy. It is optional lifecycle plumbing on top of WindowSizeClass.

The arc is not a win. It means accepting that Google never documented a clean way out of the Resizable warning, that Play behavior on Chromebooks stays largely opaque until you ship and test there, and that ChromeOS itself feels like a platform Google is letting fade while Aluminium OS and unified Android desktop take the spotlight.

What's more, there is that feeling of being treated unfairly. Google pushes developers hard on making their apps behave well on as many device categories and form factors as possible, yet even first class citizens are stigmatised by this popup.

Has anyone found a workaround, or is this firmly an OS-level restriction? Let me know in the comments if you've felt this pain, too.

References

Top comments (0)