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

推荐订阅源

博客园 - 三生石上(FineUI控件)
O
OpenAI News
WordPress大学
WordPress大学
P
Proofpoint News Feed
J
Java Code Geeks
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Register - Security
The Register - Security
Engineering at Meta
Engineering at Meta
H
Help Net Security
人人都是产品经理
人人都是产品经理
Vercel News
Vercel News
N
Netflix TechBlog - Medium
F
Full Disclosure
U
Unit 42
Latest news
Latest news
N
News and Events Feed by Topic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
InfoQ
L
LINUX DO - 最新话题
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
爱范儿
爱范儿
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
小众软件
小众软件
I
Intezer
V
V2EX
S
SegmentFault 最新的问题
C
CERT Recently Published Vulnerability Notes
阮一峰的网络日志
阮一峰的网络日志
Security Archives - TechRepublic
Security Archives - TechRepublic
Recent Announcements
Recent Announcements
C
Check Point Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Recorded Future
Recorded Future
博客园 - Franky
Project Zero
Project Zero
S
Securelist
Attack and Defense Labs
Attack and Defense Labs
Spread Privacy
Spread Privacy
The Hacker News
The Hacker News
T
The Blog of Author Tim Ferriss
Google DeepMind News
Google DeepMind News
aimingoo的专栏
aimingoo的专栏
博客园 - 叶小钗
NISL@THU
NISL@THU
云风的 BLOG
云风的 BLOG
S
Secure Thoughts
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
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