| 73 | type AndroidDeviceType = "tv" | "mobile"; |
| 74 | |
| 75 | export class AndroidRobot implements Robot { |
| 76 | |
| 77 | public constructor(private deviceId: string) { |
| 78 | } |
| 79 | |
| 80 | public adb(...args: string[]): Buffer { |
| 81 | return execFileSync(getAdbPath(), ["-s", this.deviceId, ...args], { |
| 82 | maxBuffer: MAX_BUFFER_SIZE, |
| 83 | timeout: TIMEOUT, |
| 84 | }); |
| 85 | } |
| 86 | |
| 87 | public silentAdb(...args: string[]): Buffer { |
| 88 | return execFileSync(getAdbPath(), ["-s", this.deviceId, ...args], { |
| 89 | maxBuffer: MAX_BUFFER_SIZE, |
| 90 | timeout: TIMEOUT, |
| 91 | stdio: ["pipe", "pipe", "pipe"], |
| 92 | }); |
| 93 | } |
| 94 | |
| 95 | public getSystemFeatures(): string[] { |
| 96 | return this.adb("shell", "pm", "list", "features") |
| 97 | .toString() |
| 98 | .split("\n") |
| 99 | .map(line => line.trim()) |
| 100 | .filter(line => line.startsWith("feature:")) |
| 101 | .map(line => line.substring("feature:".length)); |
| 102 | } |
| 103 | |
| 104 | public async getScreenSize(): Promise<ScreenSize> { |
| 105 | const screenSize = this.adb("shell", "wm", "size") |
| 106 | .toString() |
| 107 | .split(" ") |
| 108 | .pop(); |
| 109 | |
| 110 | if (!screenSize) { |
| 111 | throw new Error("Failed to get screen size"); |
| 112 | } |
| 113 | |
| 114 | const scale = 1; |
| 115 | const [width, height] = screenSize.split("x").map(Number); |
| 116 | return { width, height, scale }; |
| 117 | } |
| 118 | |
| 119 | public async listApps(): Promise<InstalledApp[]> { |
| 120 | // only apps that have a launcher activity are returned |
| 121 | return this.adb("shell", "cmd", "package", "query-activities", "-a", "android.intent.action.MAIN", "-c", "android.intent.category.LAUNCHER") |
| 122 | .toString() |
| 123 | .split("\n") |
| 124 | .map(line => line.trim()) |
| 125 | .filter(line => line.startsWith("packageName=")) |
| 126 | .map(line => line.substring("packageName=".length)) |
| 127 | .filter((value, index, self) => self.indexOf(value) === index) |
| 128 | .map(packageName => ({ |
| 129 | packageName, |
| 130 | appName: packageName, |
| 131 | })); |
| 132 | } |
nothing calls this directly
no outgoing calls
no test coverage detected