Compare commits

...

2 commits

Author SHA1 Message Date
Too Late (bot)
9f82ac189a
Merge 232046e986 into 47940811b4 2025-03-16 15:12:38 +01:00
47940811b4
fix #126
Some checks are pending
Android CI / build (push) Waiting to run
2025-03-16 02:30:49 +01:00
2 changed files with 67 additions and 11 deletions

View file

@ -69,10 +69,23 @@ class HomeActivity : UIObject, AppCompatActivity() {
LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
) )
// Initialise layout // Initialise layout
binding = HomeBinding.inflate(layoutInflater) binding = HomeBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
binding.root.setOnApplyWindowInsetsListener { _, windowInsets ->
val insets = windowInsets.systemGestureInsets
touchGestureDetector.setSystemGestureInsets(insets)
windowInsets
}
}
// Handle back key / gesture on Android 13+, cf. onKeyDown() // Handle back key / gesture on Android 13+, cf. onKeyDown()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

View file

@ -1,10 +1,13 @@
package de.jrpie.android.launcher.ui package de.jrpie.android.launcher.ui
import android.content.Context import android.content.Context
import android.graphics.Insets
import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.MotionEvent import android.view.MotionEvent
import android.view.ViewConfiguration import android.view.ViewConfiguration
import androidx.annotation.RequiresApi
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import kotlin.math.abs import kotlin.math.abs
@ -31,20 +34,29 @@ class TouchGestureDetector(
private val longPressHandler = Handler(Looper.getMainLooper()) private val longPressHandler = Handler(Looper.getMainLooper())
private var systemGestureInsetTop = 100
private var systemGestureInsetBottom = 0
private var systemGestureInsetLeft = 0
private var systemGestureInsetRight = 0
data class Vector(val x: Float, val y: Float) { data class Vector(val x: Float, val y: Float) {
fun absSquared(): Float { fun absSquared(): Float {
return this.x * this.x + this.y * this.y return this.x * this.x + this.y * this.y
} }
fun plus(vector: Vector): Vector { fun plus(vector: Vector): Vector {
return Vector(this.x + vector.x, this.y + vector.y) return Vector(this.x + vector.x, this.y + vector.y)
} }
fun max(other: Vector): Vector { fun max(other: Vector): Vector {
return Vector(max(this.x, other.x), max(this.y, other.y)) return Vector(max(this.x, other.x), max(this.y, other.y))
} }
fun min(other: Vector): Vector { fun min(other: Vector): Vector {
return Vector(min(this.x, other.x), min(this.y, other.y)) return Vector(min(this.x, other.x), min(this.y, other.y))
} }
operator fun minus(vector: Vector): Vector { operator fun minus(vector: Vector): Vector {
return Vector(this.x - vector.x, this.y - vector.y) return Vector(this.x - vector.x, this.y - vector.y)
} }
@ -61,16 +73,35 @@ class TouchGestureDetector(
fun sizeSquared(): Float { fun sizeSquared(): Float {
return (max - min).absSquared() return (max - min).absSquared()
} }
fun getDirection(): Vector { fun getDirection(): Vector {
return last - start return last - start
} }
fun update(vector: Vector) { fun update(vector: Vector) {
min = min.min(vector) min = min.min(vector)
max = max.max(vector) max = max.max(vector)
last = vector last = vector
} }
} }
private fun PointerPath.startIntersectsSystemGestureInsets(): Boolean {
// ignore x, since this makes edge swipes very hard to execute
return start.y < systemGestureInsetTop
|| start.y > height - systemGestureInsetBottom
}
private fun PointerPath.intersectsSystemGestureInsets(): Boolean {
return min.x < systemGestureInsetLeft
|| min.y < systemGestureInsetTop
|| max.x > width - systemGestureInsetRight
|| max.y > height - systemGestureInsetBottom
}
private fun PointerPath.isTap(): Boolean { private fun PointerPath.isTap(): Boolean {
if (intersectsSystemGestureInsets()) {
return false
}
return sizeSquared() < TOUCH_SLOP_SQUARE return sizeSquared() < TOUCH_SLOP_SQUARE
} }
@ -192,9 +223,8 @@ class TouchGestureDetector(
val mainPointerPath = paths.entries.firstOrNull { it.value.number == 0 }?.value ?: return val mainPointerPath = paths.entries.firstOrNull { it.value.number == 0 }?.value ?: return
// Ignore swipes at the very top, since this interferes with the status bar. // Ignore swipes starting at the very top and the very bottom
// TODO: replace 100px by sensible dp value (e.g. twice the height of the status bar) if (paths.entries.any { it.value.startIntersectsSystemGestureInsets() }) {
if (paths.entries.any { it.value.start.y < 100 }) {
return return
} }
@ -204,7 +234,8 @@ class TouchGestureDetector(
if (duration in 0..TAP_TIMEOUT) { if (duration in 0..TAP_TIMEOUT) {
if (timeStart - lastTappedTime < DOUBLE_TAP_TIMEOUT && if (timeStart - lastTappedTime < DOUBLE_TAP_TIMEOUT &&
lastTappedLocation?.let { lastTappedLocation?.let {
(mainPointerPath.last - it).absSquared() < DOUBLE_TAP_SLOP_SQUARE} == true (mainPointerPath.last - it).absSquared() < DOUBLE_TAP_SLOP_SQUARE
} == true
) { ) {
Gesture.DOUBLE_CLICK.invoke(context) Gesture.DOUBLE_CLICK.invoke(context)
} else { } else {
@ -239,6 +270,7 @@ class TouchGestureDetector(
gesture = Gesture.SWIPE_SMALLER gesture = Gesture.SWIPE_SMALLER
} }
} }
Gesture.SWIPE_UP -> { Gesture.SWIPE_UP -> {
if (startEndMax.x + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.x) { if (startEndMax.x + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.x) {
gesture = Gesture.SWIPE_LARGER_REVERSE gesture = Gesture.SWIPE_LARGER_REVERSE
@ -246,6 +278,7 @@ class TouchGestureDetector(
gesture = Gesture.SWIPE_SMALLER_REVERSE gesture = Gesture.SWIPE_SMALLER_REVERSE
} }
} }
Gesture.SWIPE_RIGHT -> { Gesture.SWIPE_RIGHT -> {
if (startEndMax.y + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.y) { if (startEndMax.y + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.y) {
gesture = Gesture.SWIPE_V gesture = Gesture.SWIPE_V
@ -253,6 +286,7 @@ class TouchGestureDetector(
gesture = Gesture.SWIPE_LAMBDA gesture = Gesture.SWIPE_LAMBDA
} }
} }
Gesture.SWIPE_LEFT -> { Gesture.SWIPE_LEFT -> {
if (startEndMax.y + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.y) { if (startEndMax.y + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.y) {
gesture = Gesture.SWIPE_V_REVERSE gesture = Gesture.SWIPE_V_REVERSE
@ -260,6 +294,7 @@ class TouchGestureDetector(
gesture = Gesture.SWIPE_LAMBDA_REVERSE gesture = Gesture.SWIPE_LAMBDA_REVERSE
} }
} }
else -> {} else -> {}
} }
@ -283,4 +318,12 @@ class TouchGestureDetector(
gesture?.invoke(context) gesture?.invoke(context)
} }
} }
@RequiresApi(Build.VERSION_CODES.Q)
fun setSystemGestureInsets(insets: Insets) {
systemGestureInsetTop = insets.top
systemGestureInsetBottom = insets.bottom
systemGestureInsetLeft = insets.left
systemGestureInsetRight = insets.right
}
} }