diff --git a/README.md b/README.md
index c16e8e9..17032a0 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,8 @@
This library aims at providing idiomatic `adb` bindings for go developers, in order to make it easier to write system tooling using golang.
This tool tries to take guesswork out of arbitrarily shelling out to `adb` by providing a structured, thoroughly-tested wrapper for the `adb` functions most-likely to be used in a system program.
-If `adb` must be installed in your path `PATH`. At this time, while this library may work on Windows or MacOS, only Linux is supported.
-If you would like to add support for Windows, MacOS, *BSD..., please [Submit a Pull Request](https://github.com/taigrr/adb/pulls).
+`adb` must be installed and available in your `PATH`. At this time, while this library may work on Windows or macOS, only Linux is supported.
+If you would like to add support for Windows, macOS, *BSD, etc., please [Submit a Pull Request](https://github.com/taigrr/adb/pulls).
## What is adb
@@ -14,17 +14,21 @@ If you would like to add support for Windows, MacOS, *BSD..., please [Submit a P
## Supported adb functions
-- [ ] `adb connect`
-- [ ] `adb disconnect`
-- [ ] `adb shell s`
-- [ ] `adb kill-server`
-- [ ] `adb device`
-- [ ] `adb pull`
+- [x] `adb connect`
+- [x] `adb disconnect`
+- [x] `adb shell `
+- [x] `adb kill-server`
+- [x] `adb devices`
+- [x] `adb pull`
- [ ] `adb install`
-- [ ] `adb push`
-- [ ] `adb reboot`
-- [ ] `adb shell input tap X Y`
-- [ ] `adb shell input swipe X1 Y1 X2 Y2 duration`
+- [x] `adb push`
+- [x] `adb reboot`
+- [x] `adb root`
+- [x] `adb shell input tap X Y`
+- [x] `adb shell input swipe X1 Y1 X2 Y2 duration`
+- [x] `adb shell input keyevent` (home, back, app switch)
+- [x] `adb shell wm size` (screen resolution)
+- [x] `adb shell getevent` (capture and replay tap sequences)
Please note that as this is a purpose-driven project library, not all functionality of ADB is currently supported, but if you need functionality that's not currently supported,
Feel free to [Open an Issue](https://github.com/taigrr/adb/issues) or [Submit a Pull Request](https://github.com/taigrr/adb/pulls)
diff --git a/adb.go b/adb.go
index 3b80b1f..a7d8136 100644
--- a/adb.go
+++ b/adb.go
@@ -51,10 +51,11 @@ func Connect(ctx context.Context, opts ConnOptions) (Device, error) {
}
func (d Device) ConnString() string {
- if d.Port == 0 {
- d.Port = 5555
+ port := d.Port
+ if port == 0 {
+ port = 5555
}
- return d.IP.String() + ":" + strconv.Itoa(int(d.Port))
+ return d.IP.String() + ":" + strconv.Itoa(int(port))
}
// Connect to a previously discovered device.
diff --git a/capture.go b/capture.go
index a0da9db..cf773d8 100644
--- a/capture.go
+++ b/capture.go
@@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"errors"
- "log"
"regexp"
"strconv"
"strings"
@@ -236,10 +235,7 @@ func (d Device) CaptureSequence(ctx context.Context) (t TapSequence, err error)
if errors.Is(err, ErrUnspecified) {
err = nil
}
- if errCode != 130 && errCode != -1 && errCode != 1 {
- // TODO remove log output here
- log.Printf("Expected error code 130 or -1, but got %d\n", errCode)
- }
+ _ = errCode
if stdout == "" {
return TapSequence{}, ErrStdoutEmpty
diff --git a/errors.go b/errors.go
index df377d9..7776620 100644
--- a/errors.go
+++ b/errors.go
@@ -17,6 +17,16 @@ var (
ErrResolutionParseFail = errors.New("failed to parse screen size from input text")
// ErrDestExists is returned when a pull destination file already exists.
ErrDestExists = errors.New("destination file already exists")
+ // ErrDeviceNotFound is returned when no device is connected or the target device cannot be found.
+ ErrDeviceNotFound = errors.New("device not found")
+ // ErrDeviceOffline is returned when the target device is offline.
+ ErrDeviceOffline = errors.New("device offline")
+ // ErrDeviceUnauthorized is returned when the device has not authorized USB debugging.
+ ErrDeviceUnauthorized = errors.New("device unauthorized; check the confirmation dialog on the device")
+ // ErrConnectionRefused is returned when the connection to a device is refused.
+ ErrConnectionRefused = errors.New("connection refused")
+ // ErrMoreThanOneDevice is returned when multiple devices are connected and no serial is specified.
+ ErrMoreThanOneDevice = errors.New("more than one device/emulator; use -s to specify a device")
// ErrUnspecified is returned when the exact error cannot be determined.
ErrUnspecified = errors.New("an unknown error has occurred, please open an issue on GitHub")
)
diff --git a/go.mod b/go.mod
index b3a0646..81f0c84 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,5 @@
module github.com/taigrr/adb
-go 1.26.1
+go 1.26.2
require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
diff --git a/util.go b/util.go
index 2d0da1d..e863360 100644
--- a/util.go
+++ b/util.go
@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"os/exec"
+ "strings"
"sync"
)
@@ -56,7 +57,22 @@ func execute(ctx context.Context, args []string) (string, string, int, error) {
// filterErr matches known output strings against the stderr.
//
// The inferred error type is then returned.
-// TODO: implement
func filterErr(stderr string) error {
- return nil
+ if stderr == "" {
+ return nil
+ }
+ switch {
+ case strings.Contains(stderr, "device not found"):
+ return ErrDeviceNotFound
+ case strings.Contains(stderr, "device offline"):
+ return ErrDeviceOffline
+ case strings.Contains(stderr, "device unauthorized"):
+ return ErrDeviceUnauthorized
+ case strings.Contains(stderr, "Connection refused"):
+ return ErrConnectionRefused
+ case strings.Contains(stderr, "more than one device"):
+ return ErrMoreThanOneDevice
+ default:
+ return nil
+ }
}
diff --git a/util_test.go b/util_test.go
index 43fb30c..76e5396 100644
--- a/util_test.go
+++ b/util_test.go
@@ -1,6 +1,7 @@
package adb
import (
+ "errors"
"testing"
)
@@ -8,15 +9,20 @@ func Test_filterErr(t *testing.T) {
tests := []struct {
name string
stderr string
- wantErr bool
+ wantErr error
}{
- {name: "empty stderr", stderr: "", wantErr: false},
- {name: "random output", stderr: "some warning text", wantErr: false},
+ {name: "empty stderr", stderr: "", wantErr: nil},
+ {name: "random output", stderr: "some warning text", wantErr: nil},
+ {name: "device not found", stderr: "error: device not found", wantErr: ErrDeviceNotFound},
+ {name: "device offline", stderr: "error: device offline", wantErr: ErrDeviceOffline},
+ {name: "device unauthorized", stderr: "error: device unauthorized.\nThis adb server's $ADB_VENDOR_KEYS is not set", wantErr: ErrDeviceUnauthorized},
+ {name: "connection refused", stderr: "cannot connect to daemon at tcp:5037: Connection refused", wantErr: ErrConnectionRefused},
+ {name: "more than one device", stderr: "error: more than one device/emulator", wantErr: ErrMoreThanOneDevice},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := filterErr(tt.stderr)
- if (err != nil) != tt.wantErr {
+ if !errors.Is(err, tt.wantErr) {
t.Errorf("filterErr() error = %v, wantErr %v", err, tt.wantErr)
}
})