mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
feat(android): detect focused-window package via dumpsys window
This commit is contained in:
1 parent
05125b69f5
commit
2fe01ea254
2 files changed
+70
-1
No files matched your search
@@ -251,8 +251,26 @@ func ForegroundPackage(ctx context.Context) (string, error) {
|
|||||||
return parseForegroundPackage(string(output)), nil
|
return parseForegroundPackage(string(output)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FocusedWindowPackage returns the package owning the currently focused window,
|
||||||
|
// or "" when no window is focused (e.g. mid-launch, before the app has drawn).
|
||||||
|
// Unlike ForegroundPackage, this reflects what is actually on screen:
|
||||||
|
// ResumedActivity flips to a newly launched app before its first frame renders,
|
||||||
|
// while mCurrentFocus only names the app once its window is up.
|
||||||
|
func FocusedWindowPackage(ctx context.Context) (string, error) {
|
||||||
|
adb, err := AdbBinary()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
output, err := exec.CommandContext(ctx, adb, "shell", "dumpsys", "window").Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return parseFocusedWindowPackage(string(output)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// resumedActivityPackage matches the "<package>/<activity>" component name that
|
// resumedActivityPackage matches the "<package>/<activity>" component name that
|
||||||
// dumpsys prints on ResumedActivity lines, capturing the package.
|
// dumpsys prints on ResumedActivity and mCurrentFocus lines, capturing the
|
||||||
|
// package.
|
||||||
var resumedActivityPackage = regexp.MustCompile(`([a-zA-Z][a-zA-Z0-9_.]*)/[a-zA-Z0-9_.$]+`)
|
var resumedActivityPackage = regexp.MustCompile(`([a-zA-Z][a-zA-Z0-9_.]*)/[a-zA-Z0-9_.$]+`)
|
||||||
|
|
||||||
// parseForegroundPackage extracts the foreground package from `dumpsys activity
|
// parseForegroundPackage extracts the foreground package from `dumpsys activity
|
||||||
@@ -269,6 +287,21 @@ func parseForegroundPackage(dumpsys string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseFocusedWindowPackage extracts the focused-window package from
|
||||||
|
// `dumpsys window` output by reading the mCurrentFocus component name. A
|
||||||
|
// "mCurrentFocus=null" line (no focused window) yields "".
|
||||||
|
func parseFocusedWindowPackage(dumpsys string) string {
|
||||||
|
for line := range strings.SplitSeq(dumpsys, "\n") {
|
||||||
|
if !strings.Contains(line, "mCurrentFocus") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if match := resumedActivityPackage.FindStringSubmatch(line); match != nil {
|
||||||
|
return match[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func bootCompleted(ctx context.Context) (bool, error) {
|
func bootCompleted(ctx context.Context) (bool, error) {
|
||||||
adb, err := AdbBinary()
|
adb, err := AdbBinary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -127,3 +127,39 @@ func TestParseForegroundPackage(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseFocusedWindowPackage(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
dumpsys string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "folio focused",
|
||||||
|
dumpsys: " mCurrentFocus=Window{e00f63a u0 app.folio/app.folio.MainActivity}\n mFocusedApp=ActivityRecord{c0 u0 app.folio/.MainActivity t202}",
|
||||||
|
want: "app.folio",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "settings focused",
|
||||||
|
dumpsys: " mCurrentFocus=Window{709 u0 com.android.settings/com.android.settings.SubSettings}",
|
||||||
|
want: "com.android.settings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no focused window mid-launch",
|
||||||
|
dumpsys: " mCurrentFocus=null\n mFocusedApp=null",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no focus line",
|
||||||
|
dumpsys: " some unrelated dumpsys window output\n",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
if got := parseFocusedWindowPackage(tc.dumpsys); got != tc.want {
|
||||||
|
t.Errorf("parseFocusedWindowPackage = %q, want %q", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user