"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AndroidDevice = void 0;
const device_android_debug_bridge_1 = require("./device-android-debug-bridge");
const applicationManagerPath = require("./android-application-manager");
const fileSystemPath = require("./android-device-file-system");
const constants = require("../../constants");
const _ = require("lodash");
const decorators_1 = require("../../decorators");
const constants_1 = require("../../../constants");
class AndroidDevice {
    constructor(identifier, status, $androidEmulatorServices, $logger, $devicePlatformsConstants, $logcatHelper, $injector) {
        this.identifier = identifier;
        this.status = status;
        this.$androidEmulatorServices = $androidEmulatorServices;
        this.$logger = $logger;
        this.$devicePlatformsConstants = $devicePlatformsConstants;
        this.$logcatHelper = $logcatHelper;
        this.$injector = $injector;
    }
    async init() {
        this.adb = this.$injector.resolve(device_android_debug_bridge_1.DeviceAndroidDebugBridge, {
            identifier: this.identifier,
        });
        this.applicationManager = this.$injector.resolve(applicationManagerPath.AndroidApplicationManager, { adb: this.adb, identifier: this.identifier });
        this.fileSystem = this.$injector.resolve(fileSystemPath.AndroidDeviceFileSystem, { adb: this.adb });
        let details = await this.getDeviceDetails(["getprop"]);
        if (!details || !details.name) {
            details = await this.getDeviceDetails(["cat", "/system/build.prop"]);
        }
        this.$logger.trace(details);
        const adbStatusInfo = AndroidDevice.ADB_DEVICE_STATUS_INFO[this.status];
        const type = await this.getType();
        let version = details.release;
        if (version && version.toLowerCase() === "q") {
            version = "10.0.0";
        }
        this.deviceInfo = {
            identifier: this.identifier,
            displayName: details.name,
            model: details.model,
            version,
            vendor: details.brand,
            platform: this.$devicePlatformsConstants.Android,
            status: adbStatusInfo ? adbStatusInfo.deviceStatus : this.status,
            errorHelp: adbStatusInfo ? adbStatusInfo.errorHelp : "Unknown status",
            isTablet: this.getIsTablet(details),
            type,
            connectionTypes: [constants_1.DeviceConnectionType.Local],
        };
        this.deviceInfo.connectionTypes = this.isEmulator
            ? [constants_1.DeviceConnectionType.Local]
            : [constants_1.DeviceConnectionType.USB];
        if (this.isEmulator) {
            this.deviceInfo.displayName = await this.$androidEmulatorServices.getRunningEmulatorName(this.identifier);
            this.deviceInfo.imageIdentifier = await this.$androidEmulatorServices.getRunningEmulatorImageIdentifier(this.identifier);
        }
        this.$logger.trace(this.deviceInfo);
    }
    get isEmulator() {
        return this.deviceInfo.type === constants.DeviceTypes.Emulator;
    }
    get isOnlyWiFiConnected() {
        return false;
    }
    async openDeviceLogStream() {
        if (this.deviceInfo.status === constants.CONNECTED_STATUS) {
            await this.$logcatHelper.start({
                deviceIdentifier: this.identifier,
                keepSingleProcess: true,
            });
        }
    }
    detach() {
        if (this.isEmulator) {
            this.$androidEmulatorServices.detach(this.deviceInfo);
        }
    }
    async getDeviceDetails(shellCommandArgs) {
        const parsedDetails = {};
        this.$logger.trace(`Trying to get information for Android device. Command is: ${shellCommandArgs}`);
        try {
            const details = await this.adb.executeShellCommand(shellCommandArgs);
            details.split(/\r?\n|\r/).forEach((value) => {
                const match = /(?:\[?ro\.build\.version|ro\.product|ro\.build)\.(.+?)]?(?:\:|=)(?:\s*?\[)?(.*?)]?$/.exec(value);
                if (match) {
                    parsedDetails[match[1]] = match[2];
                }
            });
        }
        catch (err) {
            this.$logger.trace(`Error while getting details from Android device. Command is: ${shellCommandArgs}. Error is: ${err}`);
        }
        this.$logger.trace(parsedDetails);
        return parsedDetails;
    }
    getIsTablet(details) {
        return (details &&
            (_.startsWith(details.release, "3.") ||
                _.includes((details.characteristics || "").toLowerCase(), "tablet")));
    }
    async getType() {
        const runningEmulatorIds = await this.$androidEmulatorServices.getRunningEmulatorIds();
        if (_.find(runningEmulatorIds, (emulatorId) => emulatorId === this.identifier)) {
            return constants.DeviceTypes.Emulator;
        }
        return constants.DeviceTypes.Device;
    }
}
exports.AndroidDevice = AndroidDevice;
AndroidDevice.ADB_DEVICE_STATUS_INFO = {
    device: {
        errorHelp: null,
        deviceStatus: constants.CONNECTED_STATUS,
    },
    offline: {
        errorHelp: "The device instance is not connected to adb or is not responding.",
        deviceStatus: constants.UNREACHABLE_STATUS,
    },
    unauthorized: {
        errorHelp: "Allow USB Debugging on your device.",
        deviceStatus: constants.UNREACHABLE_STATUS,
    },
    recovery: {
        errorHelp: "Your device is in recovery mode. This mode is used to recover your phone when it is broken or to install custom roms.",
        deviceStatus: constants.UNREACHABLE_STATUS,
    },
    "no permissions": {
        errorHelp: "Insufficient permissions to communicate with the device.",
        deviceStatus: constants.UNREACHABLE_STATUS,
    },
};
__decorate([
    (0, decorators_1.cache)()
], AndroidDevice.prototype, "init", null);
