Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cli/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ var ioTapCmd = &cobra.Command{
},
}

var longPressDuration int

var ioLongPressCmd = &cobra.Command{
Use: "longpress [x,y]",
Short: "Long press on a device screen at the given coordinates",
Expand Down Expand Up @@ -80,6 +82,7 @@ var ioLongPressCmd = &cobra.Command{
DeviceID: deviceId,
X: x,
Y: y,
Duration: longPressDuration,
}

response := commands.LongPressCommand(req)
Expand Down Expand Up @@ -186,6 +189,7 @@ func init() {
// io command flags
ioTapCmd.Flags().StringVar(&deviceId, "device", "", "ID of the device to tap on")
ioLongPressCmd.Flags().StringVar(&deviceId, "device", "", "ID of the device to long press on")
ioLongPressCmd.Flags().IntVar(&longPressDuration, "duration", 500, "duration of the long press in milliseconds")
ioButtonCmd.Flags().StringVar(&deviceId, "device", "", "ID of the device to press button on")
ioTextCmd.Flags().StringVar(&deviceId, "device", "", "ID of the device to send keys to")
ioSwipeCmd.Flags().StringVar(&deviceId, "device", "", "ID of the device to swipe on")
Expand Down
5 changes: 3 additions & 2 deletions commands/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type LongPressRequest struct {
DeviceID string `json:"deviceId"`
X int `json:"x"`
Y int `json:"y"`
Duration int `json:"duration"`
}

// TextRequest represents the parameters for a text input command
Expand Down Expand Up @@ -91,13 +92,13 @@ func LongPressCommand(req LongPressRequest) *CommandResponse {
return NewErrorResponse(fmt.Errorf("failed to start agent on device %s: %v", targetDevice.ID(), err))
}

err = targetDevice.LongPress(req.X, req.Y)
err = targetDevice.LongPress(req.X, req.Y, req.Duration)
if err != nil {
return NewErrorResponse(fmt.Errorf("failed to long press on device %s: %v", targetDevice.ID(), err))
}

return NewSuccessResponse(map[string]interface{}{
"message": fmt.Sprintf("Long pressed on device %s at (%d,%d)", targetDevice.ID(), req.X, req.Y),
"message": fmt.Sprintf("Long pressed on device %s at (%d,%d) for %dms", targetDevice.ID(), req.X, req.Y, req.Duration),
})
}

Expand Down
4 changes: 2 additions & 2 deletions devices/android.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
func (d *AndroidDevice) runAdbCommand(args ...string) ([]byte, error) {
deviceID := d.getAdbIdentifier()
cmdArgs := append([]string{"-s", deviceID}, args...)
cmd := exec.Command(getAdbPath(), cmdArgs...)

Check failure on line 143 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
return cmd.CombinedOutput()
}

Expand Down Expand Up @@ -319,8 +319,8 @@
}

// LongPress simulates a long press at (x, y) on the Android device.
func (d *AndroidDevice) LongPress(x, y int) error {
_, err := d.runAdbCommand("shell", "input", "swipe", fmt.Sprintf("%d", x), fmt.Sprintf("%d", y), fmt.Sprintf("%d", x), fmt.Sprintf("%d", y), "500")
func (d *AndroidDevice) LongPress(x, y, duration int) error {
_, err := d.runAdbCommand("shell", "input", "swipe", fmt.Sprintf("%d", x), fmt.Sprintf("%d", y), fmt.Sprintf("%d", x), fmt.Sprintf("%d", y), fmt.Sprintf("%d", duration))
if err != nil {
return err
}
Expand Down Expand Up @@ -411,7 +411,7 @@

// getAVDName returns the AVD name for an emulator, or empty string if not an emulator
func getAVDName(transportID string) string {
avdCmd := exec.Command(getAdbPath(), "-s", transportID, "shell", "getprop", "ro.boot.qemu.avd_name")

Check failure on line 414 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
avdOutput, err := avdCmd.CombinedOutput()
if err == nil && len(avdOutput) > 0 {
avdName := strings.TrimSpace(string(avdOutput))
Expand All @@ -428,7 +428,7 @@
}

// fall back to product model
modelCmd := exec.Command(getAdbPath(), "-s", deviceID, "shell", "getprop", "ro.product.model")

Check failure on line 431 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
modelOutput, err := modelCmd.CombinedOutput()
if err == nil && len(modelOutput) > 0 {
return strings.TrimSpace(string(modelOutput))
Expand All @@ -438,7 +438,7 @@
}

func getAndroidDeviceVersion(deviceID string) string {
versionCmd := exec.Command(getAdbPath(), "-s", deviceID, "shell", "getprop", "ro.build.version.release")

Check failure on line 441 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
versionOutput, err := versionCmd.CombinedOutput()
if err == nil && len(versionOutput) > 0 {
return strings.TrimSpace(string(versionOutput))
Expand All @@ -449,7 +449,7 @@

// GetAndroidDevices retrieves a list of connected Android devices
func GetAndroidDevices() ([]ControllableDevice, error) {
command := exec.Command(getAdbPath(), "devices")

Check failure on line 452 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
output, err := command.CombinedOutput()
if err != nil {
status := command.ProcessState.ExitCode()
Expand Down Expand Up @@ -533,7 +533,7 @@
defer cancel()

// launch emulator in background without context (so it persists after function returns)
cmd := exec.Command(getEmulatorPath(), "-netdelay", "none", "-netspeed", "full", "-avd", d.id, "-qt-hide-window")

Check failure on line 536 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
err := cmd.Start()
if err != nil {
return fmt.Errorf("failed to start emulator: %w", err)
Expand Down Expand Up @@ -570,7 +570,7 @@

// checkBootComplete checks if an emulator has finished booting
func (d *AndroidDevice) checkBootComplete(deviceID string) (bool, error) {
cmd := exec.Command(getAdbPath(), "-s", deviceID, "shell", "getprop", "sys.boot_completed")

Check failure on line 573 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
output, err := cmd.CombinedOutput()
if err != nil {
return false, err
Expand Down Expand Up @@ -818,7 +818,7 @@
utils.Verbose("Starting %s with app path: %s", serverClass, appPath)
cmdArgs := append([]string{"-s", d.getAdbIdentifier()}, "exec-out", fmt.Sprintf("CLASSPATH=%s", appPath), "app_process", "/system/bin", serverClass, "--quality", fmt.Sprintf("%d", config.Quality), "--scale", fmt.Sprintf("%.2f", config.Scale), "--fps", fmt.Sprintf("%d", config.FPS))
utils.Verbose("Running command: %s %s", getAdbPath(), strings.Join(cmdArgs, " "))
cmd := exec.Command(getAdbPath(), cmdArgs...)

Check failure on line 821 in devices/android.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)

stdout, err := cmd.StdoutPipe()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion devices/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type ControllableDevice interface {
Boot() error // boot simulator/emulator
Shutdown() error // shutdown simulator/emulator
Tap(x, y int) error
LongPress(x, y int) error
LongPress(x, y, duration int) error
Swipe(x1, y1, x2, y2 int) error
Gesture(actions []wda.TapAction) error
StartAgent(config StartAgentConfig) error
Expand Down
4 changes: 2 additions & 2 deletions devices/ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ func (d IOSDevice) Tap(x, y int) error {
return d.wdaClient.Tap(x, y)
}

func (d IOSDevice) LongPress(x, y int) error {
return d.wdaClient.LongPress(x, y)
func (d IOSDevice) LongPress(x, y, duration int) error {
return d.wdaClient.LongPress(x, y, duration)
}

func (d IOSDevice) Swipe(x1, y1, x2, y2 int) error {
Expand Down
4 changes: 2 additions & 2 deletions devices/simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
// runSimctl executes xcrun simctl with the provided arguments
func runSimctl(args ...string) ([]byte, error) {
fullArgs := append([]string{"simctl"}, args...)
cmd := exec.Command("xcrun", fullArgs...)

Check failure on line 114 in devices/simulator.go

View workflow job for this annotation

GitHub Actions / lint

G204: Subprocess launched with variable (gosec)
output, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("failed to execute xcrun simctl command: %w", err)
Expand Down Expand Up @@ -635,8 +635,8 @@
return s.wdaClient.Tap(x, y)
}

func (s SimulatorDevice) LongPress(x, y int) error {
return s.wdaClient.LongPress(x, y)
func (s SimulatorDevice) LongPress(x, y, duration int) error {
return s.wdaClient.LongPress(x, y, duration)
}

func (s SimulatorDevice) Swipe(x1, y1, x2, y2 int) error {
Expand Down
4 changes: 2 additions & 2 deletions devices/wda/longpress.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
)

func (c *WdaClient) LongPress(x, y int) error {
func (c *WdaClient) LongPress(x, y, duration int) error {

sessionId, err := c.GetOrCreateSession()
if err != nil {
Expand All @@ -22,7 +22,7 @@ func (c *WdaClient) LongPress(x, y int) error {
Actions: []TapAction{
{Type: "pointerMove", Duration: 0, X: x, Y: y},
{Type: "pointerDown", Button: 0},
{Type: "pause", Duration: 500},
{Type: "pause", Duration: duration},
{Type: "pointerUp", Button: 0},
},
},
Expand Down
8 changes: 8 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ type IoLongPressParams struct {
DeviceID string `json:"deviceId"`
X int `json:"x"`
Y int `json:"y"`
Duration int `json:"duration"`
}

type IoSwipeParams struct {
Expand Down Expand Up @@ -322,10 +323,17 @@ func handleIoLongPress(params json.RawMessage) (interface{}, error) {
return nil, fmt.Errorf("invalid parameters: %v. Expected fields: deviceId, x, y", err)
}

// default duration to 500ms if not provided
duration := ioLongPressParams.Duration
if duration == 0 {
duration = 500
}

req := commands.LongPressRequest{
DeviceID: ioLongPressParams.DeviceID,
X: ioLongPressParams.X,
Y: ioLongPressParams.Y,
Duration: duration,
}

response := commands.LongPressCommand(req)
Expand Down
Loading