mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07: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
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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_.$]+`)
|
||||
|
||||
// parseForegroundPackage extracts the foreground package from `dumpsys activity
|
||||
@@ -269,6 +287,21 @@ func parseForegroundPackage(dumpsys string) string {
|
||||
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) {
|
||||
adb, err := AdbBinary()
|
||||
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