UNPKG

appium-android-driver

Version:

Android UiAutomator and Chrome support for Appium

298 lines 13.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDeviceInfoFromCaps = getDeviceInfoFromCaps; exports.createADB = createADB; exports.getLaunchInfo = getLaunchInfo; exports.initDevice = initDevice; const semver = __importStar(require("semver")); const lodash_1 = __importDefault(require("lodash")); const bluebird_1 = __importDefault(require("bluebird")); const node_path_1 = __importDefault(require("node:path")); const geolocation_1 = require("../geolocation"); const io_appium_settings_1 = require("io.appium.settings"); const keyboard_1 = require("../keyboard"); const utils_1 = require("./utils"); const time_1 = require("../time"); const asyncbox_1 = require("asyncbox"); const utils_2 = require("../../utils"); /** * @this {AndroidDriver} * @returns {Promise<import('../types').ADBDeviceInfo>} */ async function getDeviceInfoFromCaps() { // we can create a throwaway ADB instance here, so there is no dependency // on instantiating on earlier (at this point, we have no udid) // we can only use this ADB object for commands that would not be confused // if multiple devices are connected const adb = await (0, utils_1.createBaseADB)(this.opts); let udid = this.opts.udid; let emPort; // a specific avd name was given. try to initialize with that if (this.opts?.avd) { await utils_1.prepareEmulator.bind(this)(adb); udid = adb.curDeviceId; emPort = adb.emulatorPort; } else { // no avd given. lets try whatever's plugged in devices/emulators this.log.info('Retrieving device list'); const devices = await adb.getDevicesWithRetry(); // udid was given, lets try to init with that device if (udid) { if (!lodash_1.default.includes(lodash_1.default.map(devices, 'udid'), udid)) { throw this.log.errorWithException(`Device ${udid} was not in the list of connected devices`); } emPort = adb.getPortFromEmulatorString(udid); } else if (this.opts.platformVersion) { this.opts.platformVersion = `${this.opts.platformVersion}`.trim(); // a platform version was given. lets try to find a device with the same os const platformVersion = semver.coerce(this.opts.platformVersion) || this.opts.platformVersion; this.log.info(`Looking for a device with Android '${platformVersion}'`); // in case we fail to find something, give the user a useful log that has // the device udids and os versions so they know what's available const availDevices = []; let partialMatchCandidate; // first try started devices/emulators for (const device of devices) { // direct adb calls to the specific device adb.setDeviceId(device.udid); /** @type {string} */ const rawDeviceOS = await adb.getPlatformVersion(); // The device OS could either be a number, like `6.0` // or an abbreviation, like `R` availDevices.push(`${device.udid} (${rawDeviceOS})`); const deviceOS = semver.coerce(rawDeviceOS) || rawDeviceOS; if (!deviceOS) { continue; } const semverPV = platformVersion; const semverDO = deviceOS; const bothVersionsCanBeCoerced = semver.valid(deviceOS) && semver.valid(platformVersion); const bothVersionsAreStrings = lodash_1.default.isString(deviceOS) && lodash_1.default.isString(platformVersion); if ((bothVersionsCanBeCoerced && /** @type {semver.SemVer} */ (semverDO).version === /** @type {semver.SemVer} */ (semverPV).version) || (bothVersionsAreStrings && lodash_1.default.toLower(deviceOS) === lodash_1.default.toLower(platformVersion))) { // Got an exact match - proceed immediately udid = device.udid; break; } else if (!bothVersionsCanBeCoerced) { // There is no point to check for partial match if either of version numbers is not coercible continue; } const pvMajor = /** @type {semver.SemVer} */ (semverPV).major; const pvMinor = /** @type {semver.SemVer} */ (semverPV).minor; const dvMajor = /** @type {semver.SemVer} */ (semverDO).major; const dvMinor = /** @type {semver.SemVer} */ (semverDO).minor; if (((!lodash_1.default.includes(this.opts.platformVersion, '.') && pvMajor === dvMajor) || (pvMajor === dvMajor && pvMinor === dvMinor)) && // Got a partial match - make sure we consider the most recent // device version available on the host system ((partialMatchCandidate && semver.gt(deviceOS, lodash_1.default.values(partialMatchCandidate)[0])) || !partialMatchCandidate)) { partialMatchCandidate = { [device.udid]: deviceOS }; } } if (!udid && partialMatchCandidate) { udid = lodash_1.default.keys(partialMatchCandidate)[0]; adb.setDeviceId(udid); } if (!udid) { // we couldn't find anything! quit throw this.log.errorWithException(`Unable to find an active device or emulator ` + `with OS ${this.opts.platformVersion}. The following are available: ` + availDevices.join(', ')); } emPort = adb.getPortFromEmulatorString(udid); } else { // a udid was not given, grab the first device we see udid = devices[0].udid; emPort = adb.getPortFromEmulatorString(udid); } } this.log.info(`Using device: ${udid}`); return { udid: String(udid), emPort: emPort ?? false }; } /** * @this {AndroidDriver} * @returns {Promise<import('appium-adb').ADB>} */ async function createADB() { // @ts-expect-error do not put arbitrary properties on opts const { udid, emPort } = this.opts; const adb = await (0, utils_1.createBaseADB)(this.opts); adb.setDeviceId(udid ?? ''); if (emPort) { adb.setEmulatorPort(emPort); } return adb; } /** * @this {AndroidDriver} * @returns {Promise<import('../types').ADBLaunchInfo | undefined>} */ async function getLaunchInfo() { let { appPackage, appActivity, appWaitPackage, appWaitActivity, app } = this.opts; if (appPackage && appActivity || (!app && !appPackage)) { return; } let apkPackage; let apkActivity; if (app) { this.log.debug(`Parsing package and activity from the '${node_path_1.default.basename(app)}' file manifest`); ({ apkPackage, apkActivity } = await this.adb.packageAndLaunchActivityFromManifest(app)); } else if (appPackage) { this.log.debug(`Parsing activity from the installed '${appPackage}' package manifest`); apkActivity = await this.adb.resolveLaunchableActivity(appPackage); } if (apkPackage && !appPackage) { appPackage = apkPackage; } if (apkActivity && !appActivity) { appActivity = apkActivity; } this.log.debug(`Resolved launch package -> activity: ${appPackage} -> ${appActivity}`); if (!appWaitPackage) { appWaitPackage = appPackage; } if (!appWaitActivity) { appWaitActivity = appActivity; } this.log.debug(`Resolved wait package -> activity: ${appWaitPackage} -> ${appWaitActivity}`); return { appPackage, appWaitPackage, appActivity, appWaitActivity }; } /** * @this {AndroidDriver} * @returns {Promise<void>} */ async function initDevice() { const { skipDeviceInitialization, locale, language, localeScript, unicodeKeyboard, hideKeyboard, disableWindowAnimation, skipUnlock, mockLocationApp, skipLogcatCapture, logcatFormat, logcatFilterSpecs, timeZone, } = this.opts; if (skipDeviceInitialization) { this.log.info(`'skipDeviceInitialization' is set. Skipping device initialization.`); } else { if (this.isEmulator()) { // Check if the device wake up only for an emulator. // It takes 1 second or so even when the device is already awake in a real device. await this.adb.waitForDevice(); } // pushSettingsApp required before calling ensureDeviceLocale for API Level 24+ // Some feature such as location/wifi are not necessary for all users, // but they require the settings app. So, try to configure it while Appium // does not throw error even if they fail. const shouldThrowError = Boolean(language || locale || localeScript || unicodeKeyboard || hideKeyboard || disableWindowAnimation || !skipUnlock); await utils_1.pushSettingsApp.bind(this)(shouldThrowError); } /** @type {Promise[]} */ const setupPromises = []; if (!this.isEmulator()) { setupPromises.push((async () => { if (mockLocationApp || lodash_1.default.isUndefined(mockLocationApp)) { await geolocation_1.setMockLocationApp.bind(this)(mockLocationApp || io_appium_settings_1.SETTINGS_HELPER_ID); } else { await this.mobileResetGeolocation(); } })()); } if (language && locale) { setupPromises.push(this.ensureDeviceLocale(language, locale, localeScript)); } if (skipLogcatCapture) { this.log.info(`'skipLogcatCapture' is set. Skipping starting logcat capture.`); } else { const logcatStartupPromise = async () => { await this.adb.startLogcat({ format: logcatFormat, filterSpecs: logcatFilterSpecs, }); this.eventEmitter.emit('syslogStarted', this.adb.logcat); if (this.adb.logcat) { this.assignBiDiLogListener(this.adb.logcat, { type: 'syslog', }); } }; setupPromises.push(logcatStartupPromise()); } setupPromises.push((async () => { if (hideKeyboard) { // Sometimes we have a race condition when Android // does not register input services soon enough // after Settings app is installed await (0, asyncbox_1.retryInterval)(3, 500, async () => await keyboard_1.hideKeyboardCompletely.bind(this)()); } else if (hideKeyboard === false) { await this.adb.shell(['ime', 'reset']); } })()); if (unicodeKeyboard) { setupPromises.push((async () => { this.log.warn(`The 'unicodeKeyboard' capability has been deprecated and will be removed. ` + `Set the 'hideKeyboard' capability to 'true' in order to make the on-screen keyboard invisible.`); await keyboard_1.initUnicodeKeyboard.bind(this)(); })()); } if (timeZone) { setupPromises.push(time_1.adjustTimeZone.bind(this)(timeZone)); } if (this.isFeatureEnabled(utils_2.GET_SERVER_LOGS_FEATURE)) { [, this._bidiServerLogListener] = this.assignBiDiLogListener(this.log.unwrap(), { type: 'server', srcEventName: 'log', entryTransformer: utils_2.nativeLogEntryToSeleniumEntry, }); } await bluebird_1.default.all(setupPromises); } /** * @typedef {import('../../driver').AndroidDriver} AndroidDriver */ //# sourceMappingURL=common.js.map