"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.installApkToDevice = exports.selectVirtualDevice = exports.selectHardwareDevice = exports.selectDeviceByTarget = exports.isLikelyEmulator = exports.findAvailableEmulatorPort = void 0; const Debug = require("debug"); const errors_1 = require("../../errors"); const log_1 = require("../../utils/log"); const adb_1 = require("./adb"); const emulator_1 = require("./emulator"); const modulePrefix = 'native-run:android:utils:run'; async function findAvailableEmulatorPort(devices, start = 5554, end = 5584) { const debug = Debug(`${modulePrefix}:${findAvailableEmulatorPort.name}`); const usedPorts = new Set(); for (const d of devices) { const m = d.serial.match(/^emulator-(\d+)$/); if (m) { usedPorts.add(Number(m[1])); } } for (let port = start; port <= end; port += 2) { if (!usedPorts.has(port)) { debug('Available emulator port found: %d', port); return port; } } debug('No available emulator ports found in range %d-%d; defaulting to 5554', start, end); return 5554; } exports.findAvailableEmulatorPort = findAvailableEmulatorPort; function isLikelyEmulator(device) { const serialEmu = /^emulator-(\d+)$/; if (serialEmu.test(device.serial)) { return true; } if (device.type === 'emulator') { return true; } const props = device.properties || {}; const deviceProp = (props['device'] || '').toLowerCase(); const productProp = (props['product'] || '').toLowerCase(); const model = (device.model || '').toLowerCase(); if (deviceProp.startsWith('emu') || deviceProp.includes('generic')) { return true; } if (productProp.includes('sdk_gphone') || productProp.includes('google_sdk')) { return true; } if (model.includes('android_sdk') || model.includes('sdk_gphone')) { return true; } return false; } exports.isLikelyEmulator = isLikelyEmulator; async function selectDeviceByTarget(sdk, devices, avds, target) { const debug = Debug(`${modulePrefix}:${selectDeviceByTarget.name}`); debug('--target %s detected', target); debug('Checking if device can be found by serial: %s', target); const device = devices.find((d) => d.serial === target); if (device) { debug('Device found by serial: %s', device.serial); return device; } const emulatorDevices = devices.filter(isLikelyEmulator); const pairAVD = async (emulator) => { let avd; try { avd = await (0, emulator_1.getAVDFromEmulator)(emulator, avds); debug('Emulator %s is using AVD: %s', emulator.serial, avd.id); } catch (e) { debug('Error with emulator %s: %O', emulator.serial, e); } return [emulator, avd]; }; debug('Checking if any of %d running emulators are using AVD by ID: %s', emulatorDevices.length, target); const emulatorsAndAVDs = await Promise.all(emulatorDevices.map((emulator) => pairAVD(emulator))); const emulators = emulatorsAndAVDs.filter((t) => typeof t[1] !== 'undefined'); const emulator = emulators.find(([, avd]) => avd.id === target); if (emulator) { const [device, avd] = emulator; debug('Emulator %s found by AVD: %s', device.serial, avd.id); return device; } debug('Checking if AVD can be found by ID: %s', target); const avd = avds.find((avd) => avd.id === target); if (avd) { debug('AVD found by ID: %s', avd.id); const port = await findAvailableEmulatorPort(devices); debug('Using emulator port: %d', port); const device = await (0, emulator_1.runEmulator)(sdk, avd, port); debug('Emulator ready, running avd: %s on %s', avd.id, device.serial); return device; } } exports.selectDeviceByTarget = selectDeviceByTarget; async function selectHardwareDevice(devices) { const hardwareDevices = devices.filter((d) => d.type === 'hardware'); // If a hardware device is found, we prefer launching to it instead of in an emulator. if (hardwareDevices.length > 0) { return hardwareDevices[0]; // TODO: can probably do better analysis on which to use? } } exports.selectHardwareDevice = selectHardwareDevice; async function selectVirtualDevice(sdk, devices, avds) { const debug = Debug(`${modulePrefix}:${selectVirtualDevice.name}`); const emulators = devices.filter((d) => d.type === 'emulator'); // If an emulator is running, use it. if (emulators.length > 0) { const [emulator] = emulators; debug('Found running emulator: %s', emulator.serial); return emulator; } throw new errors_1.AndroidRunException('No target devices/emulators available.', errors_1.ERR_NO_TARGET); } exports.selectVirtualDevice = selectVirtualDevice; async function installApkToDevice(sdk, device, apk, appId) { (0, log_1.log)(`Installing ${apk}...\n`); try { await (0, adb_1.installApk)(sdk, device, apk); } catch (e) { if (e instanceof errors_1.ADBException) { if (e.code === errors_1.ERR_INCOMPATIBLE_UPDATE || e.code === errors_1.ERR_VERSION_DOWNGRADE) { (0, log_1.log)(`${e.message} Uninstalling and trying again...\n`); await (0, adb_1.uninstallApp)(sdk, device, appId); await (0, adb_1.installApk)(sdk, device, apk); return; } } throw e; } } exports.installApkToDevice = installApkToDevice;