From 10bddf1adef22b19a3f9d1ae0732f75d9f09cced Mon Sep 17 00:00:00 2001 From: Iwo Wolanin Date: Mon, 9 Feb 2026 19:51:17 +0100 Subject: [PATCH 1/2] Fix: Allow touch events to pass through Dynamic Island overlay Fixed the issue where Dynamic Island overlay was blocking touch events to underlying UI elements (notifications, WiFi, Bluetooth settings, etc.). Changes: 1. Removed FLAG_NOT_TOUCH_MODAL which was blocking touch events to pass through 2. Added FLAG_WATCH_OUTSIDE_TOUCH to detect clicks outside the overlay 3. Implemented touch event handling to: - Close expanded island when user clicks outside - Dismiss active plugin when user clicks outside in opened state - Allow normal interaction with system UI elements behind the overlay This allows users to interact with notification panel, WiFi, Bluetooth, and other system UI elements even when Dynamic Island is active. --- .../model/service/IslandOverlayService.kt | 19 +++++++++++++------ gradlew | 0 2 files changed, 13 insertions(+), 6 deletions(-) mode change 100644 => 100755 gradlew diff --git a/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt b/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt index 7f7dd2a..4b8dd2d 100644 --- a/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt +++ b/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt @@ -42,7 +42,7 @@ class IslandOverlayService : AccessibilityService(), PluginHost { MATCH_PARENT, WRAP_CONTENT, TYPE_ACCESSIBILITY_OVERLAY, - FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_NO_LIMITS or FLAG_NOT_TOUCH_MODAL or FLAG_NOT_FOCUSABLE, + FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_NO_LIMITS or FLAG_NOT_FOCUSABLE or FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT ).apply { gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL @@ -146,13 +146,20 @@ class IslandOverlayService : AccessibilityService(), PluginHost { ) } - // TODO: Find a way to detect when a click is performed outside of the overlay (to close it) - /*composeView.setOnTouchListener { view: View?, event: MotionEvent -> - if (event.action == MotionEvent.ACTION_DOWN) { - Log.d("OverlayService", "Touch event") + // Handle clicks outside the overlay to close/shrink it + composeView.setOnTouchListener { view: View?, event: MotionEvent -> + if (event.action == MotionEvent.ACTION_OUTSIDE) { + // Click is outside the overlay bounds, shrink/close the island + if (islandState is IslandViewState.Expanded) { + shrink() + } else if (islandState is IslandViewState.Opened) { + // Dismiss the active plugin + pluginManager.requestDismiss(pluginManager.activePlugins.firstOrNull() ?: return@setOnTouchListener false) + } + Log.d("OverlayService", "Click outside overlay detected") } false - }*/ + } // Trick The ComposeView into thinking we are tracking lifecycle /*val viewModelStore = ViewModelStore() diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 56c89f75522c9c4c7d78de5f8fa6970c2d09aa1b Mon Sep 17 00:00:00 2001 From: OneDevelopmentPL Date: Mon, 9 Feb 2026 21:20:43 +0100 Subject: [PATCH 2/2] Fix: overlay touch handling; allow negative Y positioning --- .../model/service/IslandOverlayService.kt | 16 ++++++++++++---- .../angel/dynamicisland/ui/island/IslandApp.kt | 8 +++++++- .../settings/pages/PositionSizeSettingsScreen.kt | 2 +- .../res/xml/accessibility_service_config.xml | 9 ++++----- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt b/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt index 4b8dd2d..7735ae3 100644 --- a/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt +++ b/app/src/main/java/fr/angel/dynamicisland/model/service/IslandOverlayService.kt @@ -26,6 +26,7 @@ import fr.angel.dynamicisland.R import fr.angel.dynamicisland.island.Island import fr.angel.dynamicisland.island.IslandState import fr.angel.dynamicisland.island.IslandViewState +import fr.angel.dynamicisland.island.IslandSettings import fr.angel.dynamicisland.model.* import fr.angel.dynamicisland.plugins.BasePlugin import fr.angel.dynamicisland.plugins.ExportedPlugins @@ -39,11 +40,11 @@ import kotlinx.coroutines.launch class IslandOverlayService : AccessibilityService(), PluginHost { private val params = WindowManager.LayoutParams( - MATCH_PARENT, WRAP_CONTENT, - TYPE_ACCESSIBILITY_OVERLAY, - FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_NO_LIMITS or FLAG_NOT_FOCUSABLE or FLAG_WATCH_OUTSIDE_TOUCH, - PixelFormat.TRANSLUCENT + WRAP_CONTENT, + TYPE_APPLICATION_OVERLAY, + FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_NO_LIMITS or FLAG_NOT_FOCUSABLE or FLAG_NOT_TOUCH_MODAL, + PixelFormat.TRANSPARENT ).apply { gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL } @@ -110,6 +111,13 @@ class IslandOverlayService : AccessibilityService(), PluginHost { init() val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager + try { + // Apply user offset (positionY is in dp). Use absolute offset so island can reach very top. + val userOffsetPx = (IslandSettings.instance.positionY * resources.displayMetrics.density).toInt() + params.y = userOffsetPx + } catch (e: Exception) { + Log.w("OverlayService", "Failed to compute user offset: ${e.message}") + } showOverlay(windowManager, params) } diff --git a/app/src/main/java/fr/angel/dynamicisland/ui/island/IslandApp.kt b/app/src/main/java/fr/angel/dynamicisland/ui/island/IslandApp.kt index c3247ae..5993c77 100644 --- a/app/src/main/java/fr/angel/dynamicisland/ui/island/IslandApp.kt +++ b/app/src/main/java/fr/angel/dynamicisland/ui/island/IslandApp.kt @@ -34,6 +34,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import fr.angel.dynamicisland.island.Island @@ -119,7 +120,12 @@ fun IslandApp( modifier = Modifier.fillMaxWidth() ) { Box( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .pointerInput(Unit) { + // This modifier allows touch events to pass through to the background + // The island will handle its own touches via combinedClickable + }, contentAlignment = when (IslandSettings.instance.gravity) { IslandGravity.Center -> Alignment.TopCenter IslandGravity.Left -> Alignment.TopStart diff --git a/app/src/main/java/fr/angel/dynamicisland/ui/settings/pages/PositionSizeSettingsScreen.kt b/app/src/main/java/fr/angel/dynamicisland/ui/settings/pages/PositionSizeSettingsScreen.kt index 3b9192f..176beab 100644 --- a/app/src/main/java/fr/angel/dynamicisland/ui/settings/pages/PositionSizeSettingsScreen.kt +++ b/app/src/main/java/fr/angel/dynamicisland/ui/settings/pages/PositionSizeSettingsScreen.kt @@ -110,7 +110,7 @@ fun PositionSizeSettingsScreen() { title = "Position Y", extension = ".dp", value = IslandSettings.instance.positionY.toFloat(), - range = 0f..50f + range = -50f..50f ) } item { diff --git a/app/src/main/res/xml/accessibility_service_config.xml b/app/src/main/res/xml/accessibility_service_config.xml index 0a5f470..18147eb 100644 --- a/app/src/main/res/xml/accessibility_service_config.xml +++ b/app/src/main/res/xml/accessibility_service_config.xml @@ -1,11 +1,10 @@ \ No newline at end of file