mirror of
https://github.com/taigrr/adb.git
synced 2026-04-02 02:58:42 -07:00
- execute() no longer panics when adb is not found; returns ErrNotInstalled - Use sync.Once for lazy adb path lookup instead of init() - Fix Pull() checking src (device path) instead of dest (local path) - Add ErrDestExists error for Pull destination conflicts - Add -s serial flag to Push, Pull, Reboot, Root for multi-device support - Root() now parses stdout to determine actual success - Fix Shell() redundant variable redeclaration - Fix 'inconsostency' typo in KillServer doc - Add doc comments to all error variables - Update Go 1.26.0 -> 1.26.1 - Add tests: ConnString, ShortenSleep, GetLength, JSON roundtrip, SequenceImporter.ToInput, insertSleeps, parseDevices edge cases, parseScreenResolution edge cases, filterErr
108 lines
3.2 KiB
Go
108 lines
3.2 KiB
Go
package adb
|
|
|
|
import (
|
|
"context"
|
|
"regexp"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/google/shlex"
|
|
)
|
|
|
|
// Shell allows you to run an arbitrary shell command against a device.
|
|
//
|
|
// This function is useful if you need to run an obscure shell command or if
|
|
// you require functionality not provided by the exposed functions here.
|
|
// Instead of using Shell, please consider submitting a PR with the functionality
|
|
// you require.
|
|
func (d Device) Shell(ctx context.Context, command string) (stdout string, stderr string, errCode int, err error) {
|
|
cmd, err := shlex.Split(command)
|
|
if err != nil {
|
|
return "", "", 1, err
|
|
}
|
|
prefix := []string{"-s", string(d.SerialNo), "shell"}
|
|
cmd = append(prefix, cmd...)
|
|
return execute(ctx, cmd)
|
|
}
|
|
|
|
// adb shell wm size
|
|
// Physical size: 1440x3120
|
|
func (d Device) GetScreenResolution(ctx context.Context) (res Resolution, err error) {
|
|
cmd := []string{"-s", string(d.SerialNo), "shell", "wm", "size"}
|
|
stdout, _, _, err := execute(ctx, cmd)
|
|
if err != nil {
|
|
return Resolution{Width: -1, Height: -1}, err
|
|
}
|
|
return parseScreenResolution(stdout)
|
|
}
|
|
|
|
// Parses input, example:
|
|
// Physical size: 1440x3040
|
|
func parseScreenResolution(in string) (Resolution, error) {
|
|
r := regexp.MustCompile(`Physical size: ([0-9]+)x([0-9]+)`)
|
|
resStr := r.FindStringSubmatch(in)
|
|
if len(resStr) != 3 {
|
|
return Resolution{Width: -1, Height: -1}, ErrResolutionParseFail
|
|
}
|
|
w, _ := strconv.Atoi(resStr[1])
|
|
h, _ := strconv.Atoi(resStr[2])
|
|
return Resolution{Width: w, Height: h}, nil
|
|
}
|
|
|
|
func (d Device) Tap(ctx context.Context, X, Y int) error {
|
|
cmd := []string{
|
|
"-s", string(d.SerialNo), "shell",
|
|
"input", "tap",
|
|
strconv.Itoa(X), strconv.Itoa(Y),
|
|
}
|
|
_, _, _, err := execute(ctx, cmd)
|
|
return err
|
|
}
|
|
|
|
// Simulates a long press
|
|
//
|
|
// Under the hood, this calls swipe with the same start and end coordinates
|
|
// with a duration of 250ms
|
|
func (d Device) LongPress(ctx context.Context, X, Y int) error {
|
|
return d.Swipe(ctx, X, Y, X, Y, time.Millisecond*250)
|
|
}
|
|
|
|
func (d Device) Swipe(ctx context.Context, X1, Y1, X2, Y2 int, duration time.Duration) error {
|
|
cmd := []string{
|
|
"-s", string(d.SerialNo), "shell",
|
|
"input", "swipe",
|
|
strconv.Itoa(X1), strconv.Itoa(Y1),
|
|
strconv.Itoa(X2), strconv.Itoa(Y2),
|
|
strconv.Itoa(int(duration.Milliseconds())),
|
|
}
|
|
_, _, _, err := execute(ctx, cmd)
|
|
return err
|
|
}
|
|
|
|
// Equivalent to pressing the home button
|
|
//
|
|
// Calls `input keyevent KEYCODE_HOME` under the hood
|
|
func (d Device) GoHome(ctx context.Context) error {
|
|
cmd := []string{"-s", string(d.SerialNo), "shell", "input", "keyevent", "KEYCODE_HOME"}
|
|
_, _, _, err := execute(ctx, cmd)
|
|
return err
|
|
}
|
|
|
|
// Equivalent to pressing the back button
|
|
//
|
|
// Calls `input keyevent KEYCODE_BACK` under the hood
|
|
func (d Device) GoBack(ctx context.Context) error {
|
|
cmd := []string{"-s", string(d.SerialNo), "shell", "input", "keyevent", "KEYCODE_BACK"}
|
|
_, _, _, err := execute(ctx, cmd)
|
|
return err
|
|
}
|
|
|
|
// Equivalent to pushing the app switcher. You probably want to call this twice.
|
|
//
|
|
// Calls `input keyevent KEYCODE_APP_SWITCH` under the hood
|
|
func (d Device) SwitchApp(ctx context.Context) error {
|
|
cmd := []string{"-s", string(d.SerialNo), "shell", "input", "keyevent", "KEYCODE_APP_SWITCH"}
|
|
_, _, _, err := execute(ctx, cmd)
|
|
return err
|
|
}
|