Use accessibility overlays for gesture zones - #3
Open
Dragonk wants to merge 5 commits into
Open
Conversation
Built test APKs are written to dist/ (gitignored, untracked). No APKs, signing keys, or build artifacts are committed.
The gesture touch zones and visual indicators were TYPE_APPLICATION_OVERLAY windows owned by a standalone foreground LifecycleService (EdgeOverlayService). Those application overlays are hidden by HIDE_NON_SYSTEM_OVERLAY_WINDOWS on secure system screens (Settings, SubSettings), so gestures stopped working there, and Android showed the persistent "displaying over other apps" notification because of SYSTEM_ALERT_WINDOW. Extract the window logic from EdgeOverlayService into a reusable EdgeOverlayController that is created, owned, and destroyed by the already- enabled EdgeGestureAccessibilityService. Every window the controller and the indicators add now uses WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, bound to the active AccessibilityService lifecycle: trusted windows that are not hidden on secure screens and do not require SYSTEM_ALERT_WINDOW. The controller is decoupled from the concrete service through a GestureDispatcher interface (trigger + replay), keeping it testable. The existing replay/interactivity workarounds (held-zone untouchable+alpha 0, indicator-hide-before-inject grace) are preserved verbatim; behaviour change is limited to the window type and ownership. Remove the now-obsolete foreground service and boot receiver: - delete EdgeOverlayService (foreground service, notification channel, canDrawOverlays watchdog, start/stop helpers) - delete BootReceiver (only revived EdgeOverlayService; the AccessibilityService is re-bound by Android on process death/reboot without it) - drop SYSTEM_ALERT_WINDOW, FOREGROUND_SERVICE, FOREGROUND_SERVICE_SPECIAL_USE, POST_NOTIFICATIONS, RECEIVE_BOOT_COMPLETED from the manifest - drop the specialUse service metadata and the EdgeOverlayService declaration - drop the androidx.lifecycle.service / lifecycle-service catalog dependency (no LifecycleService remains) The accessibility service watchdog now only re-checks unrestricted battery and re-asserts the controller; the canDrawOverlays failure path is gone. Accessibility privacy is unchanged (canRetrieveWindowContent stays false; only the foreground package name is read for per-app pass-through). Lifecycle on service bind/unbind/rebind, configuration and display-geometry changes, and rotation are handled by the controller via the owner service.
With gesture windows owned by the AccessibilityService as TYPE_ACCESSIBILITY_OVERLAY, SYSTEM_ALERT_WINDOW / canDrawOverlays / ACTION_MANAGE_OVERLAY_PERMISSION are no longer needed. Remove that requirement from the setup card and the master-switch gating, the periodic overlay-permission re-check, and the gestures-off overlay toast path. Enabling gestures now depends only on the AccessibilityService being bound and unrestricted battery usage. - MainActivity: remove overlayGranted state, its ON_RESUME/1s poll, the ACTION_MANAGE_OVERLAY_PERMISSION intent, and the offReason overlay branch; canEnable no longer requires overlay. Replace the "restricted screens" remember bullet with an on-device/local-only one (the Settings limitation this change fixes is no longer true). - PermissionsCard: drop the overlay RequirementRow and the onRequestOverlay callback; the card now lists accessibility + battery only. - MainViewModel.setMasterEnabled: just write the datastore flag — the AccessibilityService observes the flow and attaches/detaches zones itself, so there is no foreground service to start/stop. - CompatibilityScreen: drop the "System screens" note claiming gestures won't work on Settings (no longer accurate). - strings: remove notification channel/running, permission_overlay, permission_grant, toast_gestures_off_overlay, compat_settings_*; reword the remember bullet to remember_on_device. - ExampleInstrumentedTest: accept the .debug applicationId suffix produced by the debug build type alongside com.ogesture.
- README "How it works": gesture overlays are accessibility-overlay windows owned by Ogesture's accessibility service, so they work on secure system screens and do not require "Display over other apps". Permissions list reduced from three to two (accessibility + unrestricted battery). Remove the known limitation that gestures cannot work on Settings pages — this change addresses it. - PRIVACY: permission table no longer lists SYSTEM_ALERT_WINDOW, FOREGROUND_SERVICE/FOREGROUND_SERVICE_SPECIAL_USE, POST_NOTIFICATIONS, or RECEIVE_BOOT_COMPLETED; accessibility now owns the edge overlays and performs the navigation actions.
Pure-data regression guards for the zone set (bottom/left/right), the swipe-direction mapping per zone, the Back/Home/Recents action wiring (incl. the bottom zone's swipe-and-hold Recents long action), and that every zone has positive thickness/length. The accessibility-overlay migration must preserve all of this; a silent change to the layout or action wiring now fails here.
This was referenced Aug 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Gesture windows have been migrated from
TYPE_APPLICATION_OVERLAYtoTYPE_ACCESSIBILITY_OVERLAYand are now owned byEdgeGestureAccessibilityServiceinstead of a standalone foreground overlay service.The window logic that lived in
EdgeOverlayService(a foregroundLifecycleService) was extracted into a reusableEdgeOverlayControllerthat is created inEdgeGestureAccessibilityService.onServiceConnected()and torn down inonUnbind()/onDestroy(). Every gesture-related window — the touch zones, the back arrow, and the home handle — now usesWindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY.Why
Ogesture already depends on an
AccessibilityServicefor the Back/Home/Recents navigation actions. Two problems came from drawing the gesture zones as ordinary application overlays:HIDE_NON_SYSTEM_OVERLAY_WINDOWS, which removes non-system application overlays — so Ogesture's gesture zones disappeared there and the user had to fall back to the phone's own navigation.SYSTEM_ALERT_WINDOWcause Android'sWindowManagerto generate the ongoing "displaying over other apps"AlertWindowNotificationfor the app.Because the gesture zones are an accessibility-driven feature owned by an already-enabled
AccessibilityService, they fitTYPE_ACCESSIBILITY_OVERLAY: trusted windows that are not hidden on secure screens and do not requireSYSTEM_ALERT_WINDOW. This uses the proper accessibility-overlay model for an accessibility-driven gesture feature — it does not bypass Android security; the accessibility service still requires explicit user consent.What changed
EdgeOverlayControllerowns the gesture-zone and indicator windows, created and destroyed byEdgeGestureAccessibilityService. It is decoupled from the concrete service through a smallGestureDispatcherinterface (trigger+replay).TYPE_ACCESSIBILITY_OVERLAYfor the touch-zone windows and forBackIndicator/HomeIndicator(newwindowTypeconstructor param defaulting to the accessibility overlay).SYSTEM_ALERT_WINDOWfrom the manifest, and allSettings.canDrawOverlays(...)checks, theACTION_MANAGE_OVERLAY_PERMISSIONsetup flow, the "Display over other apps" setup requirement, and the gestures-off overlay failure path.EdgeOverlayServiceand its notification channel/running notification.BootReceiver— it only revivedEdgeOverlayService. Android rebinds theAccessibilityServiceafter process death/reboot on its own, and the controller re-attaches zones if the master switch is still on, so the boot receiver is no longer needed.FOREGROUND_SERVICE,FOREGROUND_SERVICE_SPECIAL_USE,POST_NOTIFICATIONS, andRECEIVE_BOOT_COMPLETED, plus thespecialUseservice metadata and theandroidx.lifecycle.servicedependency.Accessibility privacy is unchanged:
canRetrieveWindowContentstaysfalse, and only the foreground package name is read (for per-app pass-through) — no window-content scraping, no broadened event collection.Behavior preserved
dispatchGesturerebuild()detaches all first)Validation
Static verification: production code has no functional dependency on
TYPE_APPLICATION_OVERLAY,SYSTEM_ALERT_WINDOW,Settings.canDrawOverlays, orACTION_MANAGE_OVERLAY_PERMISSION(the only remaining mentions are explanatory KDoc comments inEdgeOverlayController). The merged release manifest requests noSYSTEM_ALERT_WINDOW,FOREGROUND_SERVICE/FOREGROUND_SERVICE_SPECIAL_USE,POST_NOTIFICATIONS, orRECEIVE_BOOT_COMPLETED; the only service declared is the accessibility service and there is no receiver. Instrumentation tests were not run (no device available to the build environment).Real-device validation
Tested on a real Xiaomi/HyperOS Android device using a locally built release APK (signed with the standard Android debug keystore; no signing key was created or committed). Confirmed:
This directly validates the two main user-facing goals of the migration.