diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go index fbf89eb2..4449a268 100644 --- a/hrp/pkg/uixt/android_adb_driver.go +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -153,11 +153,11 @@ func (ad *adbDriver) PressKeyCode(keyCode KeyCode, metaState KeyMeta) (err error return } -func (ad *adbDriver) AppLaunch(bundleId string) (err error) { +func (ad *adbDriver) AppLaunch(packageName string) (err error) { // 不指定 Activity 名称启动(启动主 Activity) // adb shell monkey -p -c android.intent.category.LAUNCHER 1 sOutput, err := ad.adbClient.RunShellCommand( - "monkey", "-p", bundleId, "-c", "android.intent.category.LAUNCHER", "1", + "monkey", "-p", packageName, "-c", "android.intent.category.LAUNCHER", "1", ) if err != nil { return err @@ -165,14 +165,22 @@ func (ad *adbDriver) AppLaunch(bundleId string) (err error) { if strings.Contains(sOutput, "monkey aborted") { return fmt.Errorf("app launch: %s", strings.TrimSpace(sOutput)) } + ad.lastLaunchedPackageName = packageName return nil } -func (ad *adbDriver) AppTerminate(bundleId string) (successful bool, err error) { +func (ad *adbDriver) AppTerminate(packageName string) (successful bool, err error) { // 强制停止应用,停止 相关的进程 // adb shell am force-stop - _, err = ad.adbClient.RunShellCommand("am", "force-stop", bundleId) - return err == nil, err + _, err = ad.adbClient.RunShellCommand("am", "force-stop", packageName) + if err != nil { + return false, err + } + + if ad.lastLaunchedPackageName == packageName { + ad.lastLaunchedPackageName = "" // reset last launched package name + } + return true, nil } func (ad *adbDriver) Tap(x, y int, options ...DataOption) error { @@ -347,3 +355,34 @@ func (ad *adbDriver) StopCaptureLog() (result interface{}, err error) { content := ad.logcat.logBuffer.String() return ConvertPoints(content), nil } + +func (ad *adbDriver) GetLastLaunchedApp() (packageName string) { + return ad.lastLaunchedPackageName +} + +func (ad *adbDriver) IsAppInForeground(packageName string) (bool, error) { + if packageName == "" { + return false, errors.New("package name is not given") + } + + // adb shell dumpsys activity activities | grep mResumedActivity + output, err := ad.adbClient.RunShellCommand("dumpsys", "activity", "activities") + if err != nil { + return false, err + } + + lines := strings.Split(string(output), "\n") + isInForeground := false + + for _, line := range lines { + trimmedLine := strings.TrimSpace(line) + if strings.HasPrefix(trimmedLine, "mResumedActivity:") { + if strings.Contains(trimmedLine, packageName) { + isInForeground = true + } + break + } + } + + return isInForeground, nil +} diff --git a/hrp/pkg/uixt/android_test.go b/hrp/pkg/uixt/android_test.go index 17d61f97..b2a89037 100644 --- a/hrp/pkg/uixt/android_test.go +++ b/hrp/pkg/uixt/android_test.go @@ -353,6 +353,34 @@ func TestDriver_AppLaunch(t *testing.T) { t.Log(ioutil.WriteFile("s1.png", raw.Bytes(), 0o600)) } +func TestDriver_IsAppInForeground(t *testing.T) { + device, _ := NewAndroidDevice() + driver, err := device.NewDriver(nil) + if err != nil { + t.Fatal(err) + } + + err = driver.Driver.AppLaunch("com.android.settings") + if err != nil { + t.Fatal(err) + } + + yes, err := driver.Driver.IsAppInForeground(driver.Driver.GetLastLaunchedApp()) + if err != nil || !yes { + t.Fatal(err) + } + + _, err = driver.Driver.AppTerminate("com.android.settings") + if err != nil { + t.Fatal(err) + } + + yes, err = driver.Driver.IsAppInForeground("com.android.settings") + if err != nil || yes { + t.Fatal(err) + } +} + func TestDriver_KeepAlive(t *testing.T) { device, _ := NewAndroidDevice() driver, err := device.NewDriver(nil) diff --git a/hrp/pkg/uixt/client.go b/hrp/pkg/uixt/client.go index 5ebd9309..95a8b277 100644 --- a/hrp/pkg/uixt/client.go +++ b/hrp/pkg/uixt/client.go @@ -20,6 +20,8 @@ type Driver struct { urlPrefix *url.URL sessionId string client *http.Client + // cache the last launched package name + lastLaunchedPackageName string } func (wd *Driver) concatURL(u *url.URL, elem ...string) string { diff --git a/hrp/pkg/uixt/interface.go b/hrp/pkg/uixt/interface.go index d9706a17..501e6862 100644 --- a/hrp/pkg/uixt/interface.go +++ b/hrp/pkg/uixt/interface.go @@ -627,10 +627,14 @@ type WebDriver interface { // AppLaunch Launch an application with given bundle identifier in scope of current session. // !This method is only available since Xcode9 SDK - AppLaunch(bundleId string) error - // AppTerminate Terminate an application with the given bundle id. + AppLaunch(packageName string) error + // AppTerminate Terminate an application with the given pacakge name. // Either `true` if the app has been successfully terminated or `false` if it was not running - AppTerminate(bundleId string) (bool, error) + AppTerminate(packageName string) (bool, error) + // GetLastLaunchedApp returns the package name of the last launched app + GetLastLaunchedApp() string + // IsAppInForeground returns true if the given package is in foreground + IsAppInForeground(packageName string) (bool, error) // StartCamera Starts a new camera for recording StartCamera() error diff --git a/hrp/pkg/uixt/ios_driver.go b/hrp/pkg/uixt/ios_driver.go index 53339d8c..33bbe0ed 100644 --- a/hrp/pkg/uixt/ios_driver.go +++ b/hrp/pkg/uixt/ios_driver.go @@ -308,6 +308,9 @@ func (wd *wdaDriver) AppLaunch(bundleId string) (err error) { data := make(map[string]interface{}) data["bundleId"] = bundleId _, err = wd.httpPOST(data, "/session", wd.sessionId, "/wda/apps/launch") + if err == nil { + wd.lastLaunchedPackageName = bundleId + } return } @@ -328,6 +331,9 @@ func (wd *wdaDriver) AppTerminate(bundleId string) (successful bool, err error) if successful, err = rawResp.valueConvertToBool(); err != nil { return false, err } + if wd.lastLaunchedPackageName == bundleId { + wd.lastLaunchedPackageName = "" // reset last launched package name + } return } @@ -348,6 +354,14 @@ func (wd *wdaDriver) AppDeactivate(second float64) (err error) { return } +func (wd *wdaDriver) GetLastLaunchedApp() (packageName string) { + return wd.lastLaunchedPackageName +} + +func (wd *wdaDriver) IsAppInForeground(packageName string) (bool, error) { + return false, errors.New("not implemented") +} + func (wd *wdaDriver) Tap(x, y int, options ...DataOption) error { return wd.TapFloat(float64(x), float64(y), options...) }