Skip to content

Commit

Permalink
Merge pull request #1158 from pixel-shock/feature/swipe-gestures
Browse files Browse the repository at this point in the history
feat: Add Swipe Support - Add multi-touch Swipe support
  • Loading branch information
sds100 authored Sep 9, 2023
2 parents 386c3b5 + 8bfbd80 commit b259967
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ sealed class ActionData {
val yStart: Int,
val xEnd: Int,
val yEnd: Int,
val fingerCount: Int,
val duration: Int,
val description: String?
) : ActionData() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ object ActionDataEntityMapper {
var yStart = 0;
var xEnd = 0;
var yEnd = 0;
var fingerCount = 1;
var duration = 250;

if (splitData.isNotEmpty()) {
Expand All @@ -127,7 +128,11 @@ object ActionDataEntityMapper {
}

if (splitData.size >= 5) {
duration = splitData[4].trim().toInt()
fingerCount = splitData[4].trim().toInt()
}

if (splitData.size >= 6) {
duration = splitData[5].trim().toInt()
}

val description = entity.extras.getData(ActionEntity.EXTRA_COORDINATE_DESCRIPTION)
Expand All @@ -138,6 +143,7 @@ object ActionDataEntityMapper {
yStart = yStart,
xEnd = xEnd,
yEnd = yEnd,
fingerCount = fingerCount,
duration = duration,
description = description
)
Expand Down Expand Up @@ -450,7 +456,7 @@ object ActionDataEntityMapper {
is ActionData.AppShortcut -> data.uri
is ActionData.PhoneCall -> data.number
is ActionData.TapScreen -> "${data.x},${data.y}"
is ActionData.SwipeScreen -> "${data.xStart},${data.yStart},${data.xEnd},${data.yEnd},${data.duration}"
is ActionData.SwipeScreen -> "${data.xStart},${data.yStart},${data.xEnd},${data.yEnd},${data.fingerCount},${data.duration}"
is ActionData.Text -> data.text
is ActionData.Url -> data.url
is ActionData.Sound -> data.soundUid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,12 @@ abstract class BaseActionUiHelper<MAPPING : Mapping<A>, A : Action>(
is ActionData.SwipeScreen -> if (action.description.isNullOrBlank()) {
getString(
R.string.description_swipe_coordinate_default,
arrayOf(action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration)
arrayOf(action.fingerCount, action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration)
)
} else {
getString(
R.string.description_swipe_coordinate_with_description,
arrayOf(action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration, action.description)
arrayOf(action.fingerCount, action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration, action.description)
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.sds100.keymapper.actions

import android.text.InputType
import android.util.Log
import io.github.sds100.keymapper.R
import io.github.sds100.keymapper.actions.swipescreen.SwipePickCoordinateResult
import io.github.sds100.keymapper.actions.tapscreen.PickCoordinateResult
Expand All @@ -10,9 +9,22 @@ import io.github.sds100.keymapper.system.camera.CameraLensUtils
import io.github.sds100.keymapper.system.display.Orientation
import io.github.sds100.keymapper.system.display.OrientationUtils
import io.github.sds100.keymapper.system.intents.ConfigIntentResult
import io.github.sds100.keymapper.system.volume.*
import io.github.sds100.keymapper.util.ui.*
import timber.log.Timber
import io.github.sds100.keymapper.system.volume.DndMode
import io.github.sds100.keymapper.system.volume.DndModeUtils
import io.github.sds100.keymapper.system.volume.RingerMode
import io.github.sds100.keymapper.system.volume.RingerModeUtils
import io.github.sds100.keymapper.system.volume.VolumeStream
import io.github.sds100.keymapper.system.volume.VolumeStreamUtils
import io.github.sds100.keymapper.util.ui.MultiChoiceItem
import io.github.sds100.keymapper.util.ui.NavDestination
import io.github.sds100.keymapper.util.ui.NavigationViewModel
import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl
import io.github.sds100.keymapper.util.ui.PopupUi
import io.github.sds100.keymapper.util.ui.PopupViewModel
import io.github.sds100.keymapper.util.ui.PopupViewModelImpl
import io.github.sds100.keymapper.util.ui.ResourceProvider
import io.github.sds100.keymapper.util.ui.navigate
import io.github.sds100.keymapper.util.ui.showPopup

/**
* Created by sds100 on 26/07/2021.
Expand Down Expand Up @@ -321,6 +333,7 @@ class CreateActionViewModelImpl(
oldData.yStart,
oldData.xEnd,
oldData.yEnd,
oldData.fingerCount,
oldData.duration,
oldData.description ?: ""
)
Expand All @@ -344,6 +357,7 @@ class CreateActionViewModelImpl(
result.yStart,
result.xEnd,
result.yEnd,
result.fingerCount,
result.duration,
description
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ class PerformActionsUseCaseImpl(
}

is ActionData.SwipeScreen -> {
result = accessibilityService.swipeScreen(action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration, inputEventType)
result = accessibilityService.swipeScreen(action.xStart, action.yStart, action.xEnd, action.yEnd, action.fingerCount, action.duration, inputEventType)
}

is ActionData.Text -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,12 @@ package io.github.sds100.keymapper.actions.swipescreen
import kotlinx.serialization.Serializable

@Serializable
data class SwipePickCoordinateResult(val xStart: Int, val yStart: Int, val xEnd: Int, val yEnd: Int, val duration: Int, val description: String)
data class SwipePickCoordinateResult(
val xStart: Int,
val yStart: Int,
val xEnd: Int,
val yEnd: Int,
val fingerCount: Int,
val duration: Int,
val description: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,13 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

enum class ScreenshotType {
START,
END
}
import timber.log.Timber

class SwipePickDisplayCoordinateFragment : Fragment() {
companion object {
const val EXTRA_RESULT = "extra_result"
}

private var currentScreenshotType: ScreenshotType = ScreenshotType.START;

private val isStartScreenshot: Boolean = false;
private val isEndScreenshot: Boolean = false;

private val args: SwipePickDisplayCoordinateFragmentArgs by navArgs()
private val requestKey: String by lazy { args.requestKey }

Expand Down Expand Up @@ -128,17 +119,10 @@ class SwipePickDisplayCoordinateFragment : Fragment() {
viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) {
binding.imageViewScreenshot.pointCoordinates.collectLatest { point ->
if (point != null) {
if (currentScreenshotType == ScreenshotType.START) {
viewModel.onScreenshotStartTouch(
point.x.toFloat() / binding.imageViewScreenshot.width,
point.y.toFloat() / binding.imageViewScreenshot.height
)
} else if (currentScreenshotType == ScreenshotType.END) {
viewModel.onScreenshotEndTouch(
point.x.toFloat() / binding.imageViewScreenshot.width,
point.y.toFloat() / binding.imageViewScreenshot.height
)
}
viewModel.onScreenshotTouch(
point.x.toFloat() / binding.imageViewScreenshot.width,
point.y.toFloat() / binding.imageViewScreenshot.height
)
}
}
}
Expand All @@ -154,13 +138,7 @@ class SwipePickDisplayCoordinateFragment : Fragment() {
}
}

binding.setOnSelectScreenshotStartClick {
currentScreenshotType = ScreenshotType.START
screenshotLauncher.launch(FileUtils.MIME_TYPE_IMAGES)
}

binding.setOnSelectScreenshotEndClick {
currentScreenshotType = ScreenshotType.END
binding.setOnSelectScreenshotClick {
screenshotLauncher.launch(FileUtils.MIME_TYPE_IMAGES)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,68 +9,99 @@ import io.github.sds100.keymapper.R
import io.github.sds100.keymapper.util.ui.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.math.roundToInt


enum class ScreenshotTouchType {
START,
END
}
class SwipePickDisplayCoordinateViewModel(
resourceProvider: ResourceProvider
) : ViewModel(), ResourceProvider by resourceProvider, PopupViewModel by PopupViewModelImpl() {

public val screenshotTouchTypeStart = ScreenshotTouchType.START;
public val screenshotTouchTypeEnd = ScreenshotTouchType.END;
private val xStart = MutableStateFlow<Int?>(null)
private val yStart = MutableStateFlow<Int?>(null)
private val xEnd = MutableStateFlow<Int?>(null)
private val yEnd = MutableStateFlow<Int?>(null)
private val fingerCount = MutableStateFlow<Int?>(1)
private val duration = MutableStateFlow<Int?>(null)

private val _bitmap = MutableStateFlow<Bitmap?>(null)
private val _returnResult = MutableSharedFlow<SwipePickCoordinateResult>()
private val _screenshotTouchType = MutableStateFlow(ScreenshotTouchType.START)

private val description: MutableStateFlow<String?> = MutableStateFlow(null)

val xStartString = xStart.map {
it ?: return@map ""

it.toString()
}.stateIn(viewModelScope, SharingStarted.Lazily, "")
}.stateIn(viewModelScope, SharingStarted.Lazily, null)

val yStartString = yStart.map {
it ?: return@map ""

it.toString()
}.stateIn(viewModelScope, SharingStarted.Lazily, "")
}.stateIn(viewModelScope, SharingStarted.Lazily, null)

val xEndString = xEnd.map {
it ?: return@map ""

it.toString()
}.stateIn(viewModelScope, SharingStarted.Lazily, "")
}.stateIn(viewModelScope, SharingStarted.Lazily, null)

val yEndString = yEnd.map {
it ?: return@map ""

it.toString()
}.stateIn(viewModelScope, SharingStarted.Lazily, "")
}.stateIn(viewModelScope, SharingStarted.Lazily, null)

val fingerCountString = fingerCount.map {
it ?: return@map ""

it.toString()
}.stateIn(viewModelScope, SharingStarted.Lazily, null)

val durationString = duration.map {
it ?: return@map ""

it.toString()
}.stateIn(viewModelScope, SharingStarted.Lazily, "")
}.stateIn(viewModelScope, SharingStarted.Lazily, null)

val bitmap = _bitmap.asStateFlow()
val returnResult = _returnResult.asSharedFlow()

val isSelectStartEndSwitchEnabled:StateFlow<Boolean> = combine(bitmap) {
bitmap?.value != null
}.stateIn(viewModelScope, SharingStarted.Lazily, false)

val isDoneButtonEnabled: StateFlow<Boolean> = combine(xStart, yStart, xEnd, yEnd, duration) { xStart, yStart, xEnd, yEnd, duration ->
private val isCoordinatesValid: StateFlow<Boolean> = combine(xStart, yStart, xEnd, yEnd) { xStart, yStart, xEnd, yEnd ->
xStart ?: return@combine false
yStart ?: return@combine false
xEnd ?: return@combine false
yEnd ?: return@combine false
duration ?: return@combine false

xStart >= 0 && yStart >= 0 && xEnd >= 0 && yEnd >= 0 && duration >= 0
xStart >= 0 && yStart >= 0 && xEnd >= 0 && yEnd >= 0
}.stateIn(viewModelScope, SharingStarted.Lazily, false)

private val _bitmap = MutableStateFlow<Bitmap?>(null)
val bitmap = _bitmap.asStateFlow()
private val isOptionsValid: StateFlow<Boolean> = combine(fingerCount, duration) { fingerCount, duration ->
fingerCount ?: return@combine false
duration ?: return@combine false

private val _returnResult = MutableSharedFlow<SwipePickCoordinateResult>()
val returnResult = _returnResult.asSharedFlow()
fingerCount >= 1 && duration > 0
}.stateIn(viewModelScope, SharingStarted.Lazily, false)

private val description: MutableStateFlow<String?> = MutableStateFlow(null)
val isDoneButtonEnabled: StateFlow<Boolean> = combine(isCoordinatesValid, isOptionsValid) { isCoordinatesValid, isOptionsValid ->
isCoordinatesValid && isOptionsValid
}.stateIn(viewModelScope, SharingStarted.Lazily, false)

fun selectedScreenshot(newBitmap: Bitmap, displaySize: Point) {

_screenshotTouchType.value = ScreenshotTouchType.START;

//check whether the height and width of the bitmap match the display size, even when it is rotated.
if (
(displaySize.x != newBitmap.width
Expand Down Expand Up @@ -109,33 +140,35 @@ class SwipePickDisplayCoordinateViewModel(
this.yEnd.value = y.toIntOrNull()
}

fun setFingerCount(fingerCount: String) {
this.fingerCount.value = fingerCount.toIntOrNull()
}

fun setDuration(duration: String) {
this.duration.value = duration.toIntOrNull()
}

fun setStartOrEndCoordinates(isChecked:Boolean, type: ScreenshotTouchType) {
if (isChecked) this._screenshotTouchType.value = type
}

/**
* [screenshotXRatio] The ratio between the point where the user pressed to the width of the image.
* [screenshotYRatio] The ratio between the point where the user pressed to the height of the image.
*/
fun onScreenshotStartTouch(screenshotXRatio: Float, screenshotYRatio: Float) {
bitmap.value?.let {

val displayX = it.width * screenshotXRatio
val displayY = it.height * screenshotYRatio

xStart.value = displayX.roundToInt()
yStart.value = displayY.roundToInt()
}
}

fun onScreenshotEndTouch(screenshotXRatio: Float, screenshotYRatio: Float) {
fun onScreenshotTouch(screenshotXRatio: Float, screenshotYRatio: Float) {
bitmap.value?.let {

val displayX = it.width * screenshotXRatio
val displayY = it.height * screenshotYRatio

xEnd.value = displayX.roundToInt()
yEnd.value = displayY.roundToInt()
if (_screenshotTouchType.value == ScreenshotTouchType.START) {
xStart.value = displayX.roundToInt()
yStart.value = displayY.roundToInt()
} else {
xEnd.value = displayX.roundToInt()
yEnd.value = displayY.roundToInt()
}
}
}

Expand All @@ -145,6 +178,7 @@ class SwipePickDisplayCoordinateViewModel(
val yStart = yStart.value ?: return@launch
val xEnd = xEnd.value ?: return@launch
val yEnd = yEnd.value ?: return@launch
val fingerCount = fingerCount.value ?: return@launch
val duration = duration.value ?: return@launch

val description = showPopup(
Expand All @@ -156,7 +190,7 @@ class SwipePickDisplayCoordinateViewModel(
)
) ?: return@launch

_returnResult.emit(SwipePickCoordinateResult(xStart, yStart, xEnd, yEnd, duration, description))
_returnResult.emit(SwipePickCoordinateResult(xStart, yStart, xEnd, yEnd, fingerCount, duration, description))
}
}

Expand All @@ -166,6 +200,7 @@ class SwipePickDisplayCoordinateViewModel(
yStart.value = result.yStart
xEnd.value = result.xEnd
yEnd.value = result.yEnd
fingerCount.value = result.fingerCount
duration.value = result.duration
description.value = result.description
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface IAccessibilityService {
fun doGlobalAction(action: Int): Result<*>

fun tapScreen(x: Int, y: Int, inputEventType: InputEventType): Result<*>
fun swipeScreen(xStart: Int, yStart: Int, xEnd: Int, yEnd: Int, duration: Int, inputEventType: InputEventType): Result<*>
fun swipeScreen(xStart: Int, yStart: Int, xEnd: Int, yEnd: Int, fingerCount: Int, duration: Int, inputEventType: InputEventType): Result<*>

val isFingerprintGestureDetectionAvailable: Boolean

Expand Down
Loading

0 comments on commit b259967

Please sign in to comment.