feat(driver): optional launcher_activity on Launch RPC for multi-alias apps

This commit is contained in:
pj committed 2026-04-18 01:59:36 +07:00
1 parent 6d81e24e71
commit c4cf0ff530
11 files changed
+69 -64

No files matched your search

+5 -1
View File
@@ -9,7 +9,11 @@ import (
// matches proto/driverpb/driver.proto. The Maestro sidecar implementation
// lives under driver/maestro; tests use driver/mock.
type Driver interface {
Launch(ctx context.Context, bundleID string, clearState bool) error
// Launch asks the backend to bring the target app to the foreground.
// launcherActivity is an optional "<pkg>/<activity>" component that
// overrides the backend's default launcher resolution — needed for
// apps that declare multiple MAIN+LAUNCHER activities.
Launch(ctx context.Context, bundleID, launcherActivity string, clearState bool) error
Terminate(ctx context.Context) error
Tap(ctx context.Context, x, y int) error
+6 -2
View File
@@ -48,8 +48,12 @@ func (c *Client) WaitForHealth(ctx context.Context, pollInterval time.Duration)
}
}
func (c *Client) Launch(ctx context.Context, bundleID string, clearState bool) error {
_, err := c.stub.Launch(ctx, &driverpb.LaunchRequest{BundleId: bundleID, ClearState: clearState})
func (c *Client) Launch(ctx context.Context, bundleID, launcherActivity string, clearState bool) error {
_, err := c.stub.Launch(ctx, &driverpb.LaunchRequest{
BundleId: bundleID,
ClearState: clearState,
LauncherActivity: launcherActivity,
})
return err
}
+4 -2
View File
@@ -21,6 +21,7 @@ type fakeServer struct {
healthCalls int
launchedBundleID string
launcherActivity string
clearState bool
terminateCalls int
taps []int32
@@ -49,6 +50,7 @@ func (s *fakeServer) Launch(_ context.Context, request *driverpb.LaunchRequest)
s.mutex.Lock()
defer s.mutex.Unlock()
s.launchedBundleID = request.GetBundleId()
s.launcherActivity = request.GetLauncherActivity()
s.clearState = request.GetClearState()
return &driverpb.Empty{}, nil
}
@@ -188,10 +190,10 @@ func TestClient_LaunchAndTerminate(t *testing.T) {
client, _ := Dial(state.address)
defer client.Close()
if err := client.Launch(context.Background(), "com.example", true); err != nil {
if err := client.Launch(context.Background(), "com.example", "com.example/.MainActivity", true); err != nil {
t.Fatal(err)
}
if state.fake.launchedBundleID != "com.example" || !state.fake.clearState {
if state.fake.launchedBundleID != "com.example" || !state.fake.clearState || state.fake.launcherActivity != "com.example/.MainActivity" {
t.Errorf("launch payload wrong: %+v", state.fake)
}
if err := client.Terminate(context.Background()); err != nil {
+10 -9
View File
@@ -23,13 +23,14 @@ const (
)
type Action struct {
Kind ActionKind
BundleID string
ClearState bool
X, Y int
Selector string
Text string
Idle time.Duration
Kind ActionKind
BundleID string
LauncherActivity string
ClearState bool
X, Y int
Selector string
Text string
Idle time.Duration
}
// Driver is an in-memory Driver implementation for unit tests.
@@ -76,11 +77,11 @@ func (d *Driver) failure(kind ActionKind) error {
return d.Failures[kind]
}
func (d *Driver) Launch(ctx context.Context, bundleID string, clearState bool) error {
func (d *Driver) Launch(ctx context.Context, bundleID, launcherActivity string, clearState bool) error {
if err := d.failure(ActionLaunch); err != nil {
return err
}
d.record(Action{Kind: ActionLaunch, BundleID: bundleID, ClearState: clearState})
d.record(Action{Kind: ActionLaunch, BundleID: bundleID, LauncherActivity: launcherActivity, ClearState: clearState})
return nil
}
+1 -1
View File
@@ -29,7 +29,7 @@ func TestRecordsAllActionsInOrder(t *testing.T) {
mock := New()
ctx := context.Background()
if err := mock.Launch(ctx, "com.example", true); err != nil {
if err := mock.Launch(ctx, "com.example", "com.example/.MainActivity", true); err != nil {
t.Fatal(err)
}
if err := mock.Tap(ctx, 100, 200); err != nil {