1import * as osascript from '@expo/osascript';
2import { execFileSync } from 'child_process';
3
4import * as Log from '../../../log';
5import { Device } from './adb';
6
7function getUnixPID(port: number | string): string {
8  // Runs like `lsof -i:8081 -P -t -sTCP:LISTEN`
9  const args = [`-i:${port}`, '-P', '-t', '-sTCP:LISTEN'];
10  Log.debug('lsof ' + args.join(' '));
11  return execFileSync('lsof', args, {
12    encoding: 'utf8',
13    stdio: ['pipe', 'pipe', 'ignore'],
14  })
15    .split('\n')[0]
16    ?.trim?.();
17}
18
19/** Activate the Emulator window on macOS. */
20export async function activateWindowAsync(device: Pick<Device, 'type' | 'pid'>): Promise<boolean> {
21  if (
22    // only mac is supported for now.
23    process.platform !== 'darwin' ||
24    // can only focus emulators
25    device.type !== 'emulator'
26  ) {
27    return false;
28  }
29
30  // Google Emulator ID: `emulator-5554` -> `5554`
31  const androidPid = device.pid!.match(/-(\d+)/)?.[1];
32  if (!androidPid) {
33    return false;
34  }
35  // Unix PID
36  const pid = getUnixPID(androidPid);
37
38  if (!pid) {
39    return false;
40  }
41  try {
42    await osascript.execAsync(`
43    tell application "System Events"
44      set frontmost of the first process whose unix id is ${pid} to true
45    end tell`);
46    return true;
47  } catch {
48    // noop -- this feature is very specific and subject to failure.
49    return false;
50  }
51}
52