Skip to content

[Unresolved] HyperOS one-handed mode: blocker rect still drifts with display-area transform #1

@Overbaker

Description

@Overbaker

Problem

On Xiaomi HyperOS (tested on Xiaomi 13 Ultra, HyperOS 2.x), when the user activates one-handed mode (单手模式), the SurfaceFlinger compositor applies a display-area transform that shifts the entire screen content downward. The One Patch blocker rectangle, regardless of which attach mechanism is used, drifts with this transform — defeating the original intent of "pinning the blocker at a fixed physical screen region".

Approaches Tried (All Failed Real-Device Validation)

# Approach Status
1 TYPE_ACCESSIBILITY_OVERLAY (v1, trusted overlay) ❌ Drifts. Trusted ≠ transform-immune.
2 AccessibilityService.attachAccessibilityOverlayToDisplay() (Android 14+, display-attached SurfaceControl) ❌ Drifts. HyperOS forks SurfaceFlinger and applies the transform to display-attached layers as well.
3 Reverse LayoutParams compensation (closed-loop OnPreDrawListener + getLocationOnScreen ↔ reverse update) ⚠️ Partial. getLocationOnScreen returns the ViewRootImpl-reported position, which on HyperOS does NOT fully reflect the underlying SurfaceFlinger transform. Compensation eliminates "reported drift" but leaves residual visual mismatch.

Why Public APIs Cannot Solve This

Verified via grok-search multi-angle research + AOSP source review:

Signal HyperOS behavior
Broadcast Intent None
onConfigurationChanged / Configuration.screenHeightDp Not triggered
WindowInsets / onApplyWindowInsetsListener Insets unchanged
DisplayManager.DisplayListener.onDisplayChanged Inconsistent across ROMs
Settings.System ContentObserver Key names ROM-private; not triggered via gesture
View.getMatrix() Reflects only view-local matrix
AccessibilityService.onMotionEvent() selective drop API returns void; cannot consume
TouchInteractionController Requires touch-exploration; conflicts with TalkBack
Reflection on ViewRootImpl.mTranslator / mInvCompatScale @hide; API 28+ reflection denylist

The only working path is what Xiaomi's Game Turbo uses — inputflinger injection in system_server — which requires platform-signature privileges unavailable to third-party apps.

Position Coordinate Three-Layer Model

Android exposes only one of three layers to apps:

  • (a) Physical pixel position — hardware level, NO public API
  • (b) SurfaceFlinger composited positiondumpsys SurfaceFlinger / Winscope only
  • (c) ViewRootImpl-reported positiongetLocationOnScreen(), the ONLY signal apps can read; ROM-dependent accuracy

Current Best-Effort Behavior (shipped)

User-toggleable in settings (屏蔽区物理坐标锁定):

  • ON (default): Reverse LayoutParams compensation. Eliminates reported drift; residual compositor drift on HyperOS unavoidable.
  • OFF: Legacy step-aside behavior. Blocker auto-pauses when displaced, resumes on full-screen.

Acceptance

Public-API platform limitation, not a bug. Keeping open as research thread:

  • If a future Android API exposes compositor transform queries → revisit
  • If HyperOS aligns SurfaceFlinger transform with getLocationOnScreen → revisit
  • If platform-signed alternative becomes feasible → revisit

Workaround for HyperOS Users

Disable 屏蔽区物理坐标锁定 switch — accept v1 step-aside behavior during one-handed mode.

Related Archived Specs

  • openspec/changes/archive/2026-04-28-fix-fab-bugs/
  • openspec/changes/archive/2026-04-28-physical-display-overlay/
  • openspec/changes/archive/2026-04-29-transform-compensation-overlay/

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is neededwontfixThis will not be worked on

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions