惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
Vulnerabilities – Threatpost
Blog — PlanetScale
Blog — PlanetScale
G
Google Developers Blog
M
MIT News - Artificial intelligence
C
Cybersecurity and Infrastructure Security Agency CISA
MyScale Blog
MyScale Blog
P
Privacy International News Feed
MongoDB | Blog
MongoDB | Blog
Know Your Adversary
Know Your Adversary
P
Palo Alto Networks Blog
AWS News Blog
AWS News Blog
Cisco Talos Blog
Cisco Talos Blog
Malwarebytes
Malwarebytes
aimingoo的专栏
aimingoo的专栏
T
Threat Research - Cisco Blogs
Last Week in AI
Last Week in AI
量子位
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
CERT Recently Published Vulnerability Notes
Hugging Face - Blog
Hugging Face - Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Y
Y Combinator Blog
L
LangChain Blog
L
LINUX DO - 热门话题
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
V
Visual Studio Blog
S
Security @ Cisco Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
O
OpenAI News
N
News | PayPal Newsroom
Stack Overflow Blog
Stack Overflow Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
V2EX - 技术
李成银的技术随笔
Recent Announcements
Recent Announcements
C
Check Point Blog
Attack and Defense Labs
Attack and Defense Labs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
Security Archives - TechRepublic
小众软件
小众软件
博客园 - 聂微东
月光博客
月光博客
GbyAI
GbyAI
T
Troy Hunt's Blog
S
Securelist
雷峰网
雷峰网

DEV Community

Understanding Optimistic Preloading in Modern Applications Nobody Wants to Read Your Code (And You Don't Want to Read Theirs) A clothing pairing app E2B vs E4B vs 31B Dense: The Practical Guide to Choosing the Right Gemma 4 Model I built an AI app store screenshot generator because Figma made me cry — looking for brutal feedback Hello DEV Community — My Developer Journey Begins The WordPress Paradox: Why It’s Here to Stay (and How to Stop Ruining It) I built a local voice AI that can change to 9 different personalities! UXRay: I Built an AI That Roasts Your UI Like a Senior Designer Would Wyrly DI: Type-safe Dependency Injection for Modern TypeScript The contract is the interface: agent-driven Steampipe Stave in one command Gemma 4's Hidden Superpower: Why Built-in Thinking Tokens Change Everything for Evaluation Tasks ⚡ WordPress Performance: The Real Truth They Don't Tell You A Mobile App Usually Needs an Admin System First Customer Portals Should Remove Repeated Admin Work Episode 4: The Time Loop (Layers & Caching) I Built ContextForge with Gemma 4: A Project Memory Generator for Developers and AI Coding Agents Why shadow DOM beat iframe for inline tooltips HOW TO CREATE USER AND ASSIGN ROLES IN AZURE WITH ENTRA ID When AI Blackmail Goes Viral Episode 3: The Secret Scroll (The Dockerfile) Monte Carlo Simulation for Engineers: Turning Uncertainty Into Numbers The tokens-per-byte trap: character-level 'compression' adds tokens Nobody Reads Your Code Anymore Why I built a collection of 5 free, zero-signup career finance tools for solo builders 🚀 New React Challenge: Instant UI with useOptimistic Resolvendo a Alucinação da IA na Arquitetura de Software com Code Property Graphs e .NET 9 S1 — Clean Backtrace Crashes: How to Diagnose and Fix Them Cómo solucionar el bucle infinito en useEffect con objetos y arrays The Brutal Reality of Running Gemma 4 Locally I made Claude Code refuse to write code unless the ticket scores 80/100 I Fed React's Entire Hooks Transition History to Gemma 4. Here's What It Found That We Missed. Building a Private RAG System: Lessons from a Local-First AI Journal CodePulse AI — Reviving an AI-Powered Repository Intelligence Platform How to Split Video into Segments with FFmpeg (CLI + API) I've audited dozens of estate agency websites. The same 5 problems show up every single time. Part 1: Taming Asynchronous JavaScript: How to Build a "Mailbox" Queue Building My AI-Powered VS Code Extension 🚀 Google Login in Express with PassportJS & JWT Great example of Gemma 4 moving beyond chatbots into real-world decision support. Using AI to guide everyday actions like recycling shows how impactful applied LLMs can be when designed for usability, not just capability. #Gemma4 #AI #Sustainability Building a Production AI Chatbot for an Educational Institute: Architecture, Lessons & Full Stack Deep-Dive Google Login in Express with PassportJS & JWT How I reclaimed 47GB on my MacBook by cleaning developer project junk Operators Are Not Oracles: How We Learned to Stop Worrying and Love the Configuration I Built 6 Free Developer Tools for AI APIs, Cron, Docker, and Self-Hosting How I Built a Real-Time Precious Metals Price Feed for 30,000 Concurrent Users in Laravel How to Use a SERP API to Validate Whether a Project Idea Is Worth Building Gemma 4 discussions often focus on capability, but real-world impact depends on deployment context. For offline education, especially in low-connectivity regions, latency, cost, and local inference matter as much as model strength. Local Mind Explores it Space Complexity + Ω and Θ Notations Google I/O 2026 Just Confirmed the Shift From AI Chatbots to AI Agents How to Add API Monitoring to an Express App in 5 Minutes (2026) Designing an In-Game Inflation Tracking Algorithm for Web Utility Apps Google AI Studio Just Changed the Shape of App Development If you struggle to learn then this is for you. Best AI Agent Security & Guardrails Tools in 2026: LLM Guard vs NeMo vs Guardrails AI Building Dynamic RBAC in React 19: From Permission Strings to Component-Level Access Control How to Build a Self-Hosted AI Code Review Tool in Python Why We Switched from React to HTMX in Production: A 200-Site Case Study Gemma-Loom: The Intent-Based Virtual Machine (IVM) for Edge Sovereignty Java实习海投攻略:3天300个沟通,我是怎么拿到面试的 I Deployed Netflix's Web Server in 30 Seconds (And So Can You) - Docker Project 1 Debugging Android 14 WebRTC Disconnects on a coturn Relay Path 1/30 Days System Design Question Testing FastAPI + SQLAlchemy with Real PostgreSQL Fixtures: No More Mocking Misery FAQ Schema Markup Generators: What They Actually Do (and What They Don't Tell You) How a pure-TypeScript flex layout engine closed the last WASM-Yoga gap Spot instances as GitHub Actions runners Agents Need Receipts, Not Just Better Prompts readmegen — Generate beautiful README.md in seconds (12 templates, open source) When AI Reads Blueprints: The Hidden Attack Surface of Multimodal Engineering Intelligence Simplicity scales — complexity kills side projects AI does exactly what you ask — that's the problem How a model upgrade silently broke our extraction prompt (and how we caught it) The Best Form Backend for Static Sites in 2026 # ⛽ I Built a Cross-Platform Fuel Finder with React & Supabase: The Indie Dev Journey The 11 Major Cloud Service Providers in 2025 Membangun Karya Visual: Mengintip Fasilitas Multimedia dan Studio Kreatif Amikom What Is IOPS? Visualizing Database Design: From Interactive Canvas to Drizzle, Prisma, and SQL in Real-time A tool to make your GitHub README impossible to ignore 🚀 Zero-Downtime Blue-Green and IP-Based Canary Deployments on ECS Fargate I reproduced a Claude Code RCE. The bug pattern is everywhere. We Replaced Our RAG Pipeline With Persistent KV Cache. Here's What We Found. Jenkins CI/CD Pipeline for a Dockerized Node.js Application: Manual Trigger vs Automatic Trigger Using GitHub Webhooks How to Stream Live Forex Rates to Google Sheets API: A Complete Guide Small Models Will Beat Giant Models (And Most People Haven’t Realized Why Yet) How I Built 5 Linux Automation Scripts on AWS EC2 I built TokenPatch to measure AI coding cost per applied patch I built a Chrome extension to stop squinting at the web Producer audit clean, six tests red Conversa — A Multi-Agent AI Platform Powered by Gemma 4 Build a Real Agent in 15 Minutes with Gemini's New Managed Agents API What I Actually Build: AI Systems That Ship, Not Demos That Impress The Box Ticked While You Read This: LinkedIn, AI Training, and the Switch You Did Not Flip Investasi Masa Depan: Mengintip Fasilitas Laboratorium Komputer Kelas Dunia di Yogyakarta I Cancelled My $20 Claude Cowork Plan After a Week With OpenWork Stop Reviewing Every Line of AI Code - Build the Trust Stack Instead How To Build an Image Cropper in Browser (Simple Steps) I built a macOS disk cleaner for developers and just launched it would love feedback Membangun Kompetensi dan Relasi: Mengapa Ekosistem Kampus Itu Penting
Adaptable apps on ChromeOS: a post-mortem
Thomas Künne · 2026-05-23 · via DEV Community

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. Sideloads 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. Sideloading 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