fix #126
Some checks are pending
Android CI / build (push) Waiting to run

This commit is contained in:
Josia Pietsch 2025-03-16 02:30:49 +01:00
parent 72f9c0595f
commit 47940811b4
Signed by: jrpie
GPG key ID: E70B571D66986A2D
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
} }
@ -128,8 +159,8 @@ class TouchGestureDetector(
} }
// add new pointers // add new pointers
for(i in 0..<event.pointerCount){ for (i in 0..<event.pointerCount) {
if(paths.containsKey(event.getPointerId(i))) { if (paths.containsKey(event.getPointerId(i))) {
continue continue
} }
val index = pointerIdToIndex[i] ?: continue val index = pointerIdToIndex[i] ?: continue
@ -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 {
@ -233,34 +264,38 @@ class TouchGestureDetector(
val startEndMax = mainPointerPath.start.max(mainPointerPath.last) val startEndMax = mainPointerPath.start.max(mainPointerPath.last)
when (gesture) { when (gesture) {
Gesture.SWIPE_DOWN -> { Gesture.SWIPE_DOWN -> {
if(startEndMax.x + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.x) { if (startEndMax.x + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.x) {
gesture = Gesture.SWIPE_LARGER gesture = Gesture.SWIPE_LARGER
} else if (startEndMin.x - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.x) { } else if (startEndMin.x - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.x) {
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
} else if (startEndMin.x - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.x) { } else if (startEndMin.x - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.x) {
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
} else if (startEndMin.y - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.y) { } else if (startEndMin.y - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.y) {
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
} else if (startEndMin.y - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.y) { } else if (startEndMin.y - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.y) {
gesture = Gesture.SWIPE_LAMBDA_REVERSE gesture = Gesture.SWIPE_LAMBDA_REVERSE
} }
} }
else -> { }
else -> {}
} }
if (edgeActions) { if (edgeActions) {
@ -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
}
} }