#!/bin/bash
# ---------------------------------------------------------------------------
# Filename :    - Android-lib.sh
# Description:  - Android public interface
# Author:       - wenjian.xiong@cixtech.com
# notes:
# ---------------------------------------------------------------------------

# ---------------------------------------------------------------------------
# Description:   同步测试机时间
# parameter:     无
# ---------------------------------------------------------------------------
sync_time(){
    adb root
    sleep 10
    # 同步测试机时间
    echo "Synchronizing device time with Linux time"
    adb shell "date $(date -d @$((`date +%s`)) '+%m%d%H%M%Y.%S')"
    # 打印Linux主机的当前时间
    echo "Linux Host Time is: $(date '+%Y-%m-%d %H:%M:%S')"
    # 打印测试机当前时间
    echo "Android Device Time is: $(adb shell "date '+%Y-%m-%d %H:%M:%S'")"
}

# ---------------------------------------------------------------------------
# Description:   打印输出，显示当前时间
# parameter:     需要打印的信息
# ---------------------------------------------------------------------------
print_output(){
    local message=$1
    local device_time=$(date '+%Y-%m-%d %H:%M:%S')
    echo "$device_time: $message"
}

# ---------------------------------------------------------------------------
# Description:   输出测试的正常信息
# parameter:     测试操作
# ---------------------------------------------------------------------------
Execution_pass(){
    local operation="$1"
    print_output "${operation} pass" | tee -a "${RESULT_FILE}"
}

# ---------------------------------------------------------------------------
# Description:   输出测试的异常信息
# parameter1:    测试操作
# parameter2:    测试用例编号
# ---------------------------------------------------------------------------
Execution_fail(){
    local operation="$1"
    local test_case="$2"
    print_output "${operation} fail" | tee -a "${RESULT_FILE}"
    print_output "${test_case} test fail" | tee -a "${RESULT_FILE}"
    kill $LOGCAT_PID 2>/dev/null
    exit 1
}

# ---------------------------------------------------------------------------
# Description:   运行ADB指令，设置超时时间
# parameter:     ADB指令
# ---------------------------------------------------------------------------
run_adb_cmd(){
    local cmd="$1"
    local timeout_seconds="${2:-180}"  # 设置超时时间，默认180s
    if [ -z "$cmd" ]; then
        print_output "Error: Empty adb command provided." | tee -a "$LOGFILE"
        return 1
    fi
    print_output "Running: $cmd with timeout of ${timeout_seconds}s" | tee -a "$LOGFILE"
    # 运行ADB指令，设置超时时间
    (timeout "$timeout_seconds" bash -c "$cmd" 2>&1) && sleep 15
    local return_code=$?
    if [ $return_code -eq 0 ]; then
        print_output "Executing adb command pass: $cmd" >> "$LOGFILE"
        return 0
    elif [ $return_code -eq 124 ]; then
        print_output "Command '$cmd' timed out after ${timeout_seconds}s" | tee -a "$LOGFILE"
        return 1
    else
        print_output "Executing adb command fail: $cmd" | tee -a "$LOGFILE"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查adb devices状态
# parameter:     无
# ---------------------------------------------------------------------------
devices_state(){
    local attempt=1
    local max_attempts=5
    local adb_devices_output=""
    while [ $attempt -lt $max_attempts ]
    do
        print_output "Attempt $attempt: Checking adb devices..." | tee -a "$LOGFILE"
        adb_devices_output=$(adb devices | grep -E "device$")
        # 检查adb devices结果
        if [ -n "$adb_devices_output" ]; then
            print_output "adb devices check pass,${adb_devices_output} exist" | tee -a "${LOGFILE}"
            return 0
        else
            print_output "adb devices check fail on attempt $attempt" | tee -a "${LOGFILE}"
            run_adb_cmd "adb kill-server"
            run_adb_cmd "adb start-server"
        fi
        attempt=$((attempt + 1))
        sleep 20
    done

    print_output "adb devices check fail after $max_attempts attempts" | tee -a "${LOGFILE}"
    return 1
}

# ---------------------------------------------------------------------------
# Description:   检查adb shell id结果
# parameter:     无
# ---------------------------------------------------------------------------
shell_id_state(){
    local id_output=$(adb shell id)
    if echo "$id_output" | grep -q "uid" && echo "$id_output" | grep -q "gid"; then
        print_output "adb shell id is ${id_output}" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "adb shell id test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查adb version结果
# parameter:     无
# ---------------------------------------------------------------------------
adb_version(){
    local adb_version_output=$(adb version | grep -E "Android Debug Bridge version.*")
    if [ -n "$adb_version_output" ]; then
        print_output "adb version is ${adb_version_output}" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "adb version test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb push大小比对
# parameter1:    PC资源路径
# parameter2:    测试机拷贝路径
# ---------------------------------------------------------------------------
check_push_size(){
    local SOURCE_SIZE=$(wc -c < "$1" | awk '{print $1}')
    local PUSH_SIZE=$(adb shell "wc -c < $2" | awk '{print $1}')
    if [ "$PUSH_SIZE" -eq "$SOURCE_SIZE" ];then
        print_output "Size matching: $PUSH_SIZE = $SOURCE_SIZE" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "Sizes mismatch: $PUSH_SIZE != $SOURCE_SIZE" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb pull大小比对
# parameter1:    测试机资源路径
# parameter2:    PC拷贝路径
# ---------------------------------------------------------------------------
check_pull_size(){
    local SOURCE_SIZE=$(adb shell "wc -c < $1" | awk '{print $1}')
    local PULL_SIZE=$(wc -c < "$2" | awk '{print $1}')
    if [ "$PULL_SIZE" -eq "$SOURCE_SIZE" ];then
        print_output "Size matching: $PULL_SIZE = $SOURCE_SIZE" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "Sizes mismatch: $PULL_SIZE != $SOURCE_SIZE" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查应用包是否install
# parameter:     应用包名
# ---------------------------------------------------------------------------
check_package_install(){
    local package_name="$1"
    local INSTALL_OUTPUT=$(adb shell pm list packages | grep "$package_name")
    if [ -n "$INSTALL_OUTPUT" ]; then
        print_output "install package is ${INSTALL_OUTPUT}," | tee -a "${LOGFILE}"
        return 0
    else
        print_output "adb install $package_name fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查应用包是否uninstall
# parameter:     应用包名
# ---------------------------------------------------------------------------
check_package_uninstall(){
    local package_name="$1"
    local UNINSTALL_OUTPUT=$(adb shell pm path "$package_name")
    if [ -z "$UNINSTALL_OUTPUT" ]; then
        print_output "uninstall package is $package_name" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "adb uninstall test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查adb bugreport结果
# parameter:     无
# ---------------------------------------------------------------------------
adb_bugreport(){
    BUGREPORT_LOG="bugreport.log"
    adb bugreport > "$BUGREPORT_LOG"  
    BUGREPORT_ZIP_FILES=$(ls | grep "bugreport.*\.zip") 
    if [ -n "${BUGREPORT_ZIP_FILES}" ]; then
        print_output "Found bugreport zip files: ${BUGREPORT_ZIP_FILES}" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "adb bugreport test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   重启到bootloader模式,解锁oem
# parameter:     无
# ---------------------------------------------------------------------------
oem_unlock(){
    # 重启到bootloader模式
    run_adb_cmd "adb root"
    run_adb_cmd "adb reboot bootloader"
    sleep 180
    FASTBOOT_STATUS=$(fastboot devices | grep -q "$ANDROID_SERIAL"; echo $?)
    if [ "$FASTBOOT_STATUS" -eq 0 ]; then
        print_output "fastboot devices check pass" | tee -a "${LOGFILE}"
    else
        print_output "fastboot devices check fail" | tee -a "${LOGFILE}"
        return 1
    fi

    # 解锁oem,检查是否解锁
    fastboot oem unlock
    UNLOCK_STATUS=$(fastboot getvar unlocked 2>&1 | grep -q "yes"; echo $?)
    if [ "$UNLOCK_STATUS" -eq 0 ]; then
        print_output "fastboot oem unlock pass" | tee -a "${LOGFILE}"
    else
        print_output "fastboot oem unlock fail" | tee -a "${LOGFILE}"
        return 1
    fi

    # 重启设备
    fastboot reboot
    sleep 120
}

# ---------------------------------------------------------------------------
# Description:   禁用verity
# parameter:     无
# ---------------------------------------------------------------------------
disable_verity(){
    run_adb_cmd "adb root"
    run_adb_cmd "adb disable-verity"
    run_adb_cmd "adb reboot"
    sleep 120
}

# ---------------------------------------------------------------------------
# Description:   adb remount，检查remount结果
# parameter:     无
# ---------------------------------------------------------------------------
remount_state(){
    run_adb_cmd "adb root"
    run_adb_cmd "adb remount"
    local MOUNT_OUTPUT=$(adb shell mount | grep '/system/')
    if echo "$MOUNT_OUTPUT" | grep -q 'rw'; then
        print_output "Remount successful: $MOUNT_OUTPUT" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "adb remount fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb root，检查root结果
# parameter:     无
# ---------------------------------------------------------------------------
root_state(){
    run_adb_cmd "adb root"
    local ROOT_STATUS=$(adb shell getprop service.adb.root)
    if [ "$ROOT_STATUS" == "1" ]; then
        print_output "root state is $ROOT_STATUS" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "ADB root test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb unroot，检查unroot结果
# parameter:     无
# ---------------------------------------------------------------------------
unroot_state(){
    run_adb_cmd "adb unroot"
    sleep 10
    local UNROOT_STATUS=$(adb shell getprop service.adb.root)
    if [ "$UNROOT_STATUS" == "0" ]; then
        print_output "unroot state is $UNROOT_STATUS" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "ADB unroot test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查USB_STATUS结果
# parameter:     无
# ---------------------------------------------------------------------------
usb_state(){
    local USB_STATUS=$(adb shell getprop sys.usb.config)
    if [ "$USB_STATUS" = "adb" ]; then
        print_output "sys.usb.config is $USB_STATUS" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "sys.usb.config test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查adb监听端口
# parameter:     无
# ---------------------------------------------------------------------------
tcpip_port(){
    run_adb_cmd "adb tcpip 5555"
    local TCP_PORT=$(adb shell getprop service.adb.tcp.port)
    if [ "$TCP_PORT" -eq 5555 ]; then
        print_output "service.adb.tcp.port is $TCP_PORT" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "service.adb.tcp.port test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查adb reboot结果
# parameter:     无
# ---------------------------------------------------------------------------
boot_completed(){
    local BOOT_COMPLETE=$(adb shell getprop sys.boot_completed)
    if [ "$BOOT_COMPLETE" -eq 1 ]; then
        print_output "BOOT_COMPLETE check pass" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "BOOT_COMPLETE check fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb forward，检查forward结果
# parameter:     无
# ---------------------------------------------------------------------------
forward_tcp(){
    run_adb_cmd "adb forward tcp:8080 tcp:8080"
    local IS_FORWARD=$(adb forward --list | grep "tcp:8080")  
    if [ -n "$IS_FORWARD" ]; then  
        print_output "Forward check is $IS_FORWARD"  | tee -a "${LOGFILE}"
        return 0
    else
        print_output "Forward check fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb forward remove，检查forward remove结果
# parameter:     无
# ---------------------------------------------------------------------------
re_forward_tcp(){
    run_adb_cmd "adb forward --remove tcp:8080"
    local RE_FORWARD=$(adb forward --list | grep "tcp:8080")  
    if [ -z "$RE_FORWARD" ]; then  
        print_output "Forward remove pass"  | tee -a "${LOGFILE}"
        return 0
    else
        print_output "Forward remove fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   adb usb恢复端口
# parameter:     无
# ---------------------------------------------------------------------------
re_tcpip_port(){
    run_adb_cmd "adb usb"
    local TCP_PORT=$(adb shell getprop service.adb.tcp.port)
    if [ "$TCP_PORT" -eq 0 ]; then
        print_output "service.adb.tcp.port is $TCP_PORT" | tee -a "${LOGFILE}"
        return 0
    else
        print_output "service.adb.tcp.port2 test fail" | tee -a "${LOGFILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查应用是否运行
# parameter:     应用包名
# ---------------------------------------------------------------------------
running_apk(){
    local RUNNING_APPS=$(adb shell ps | grep "$1")  
    if [ -n "$RUNNING_APPS" ]; then  
        print_output "App is running: $RUNNING_APPS" | tee -a "$LOGFILE"
        return 0
    else
        print_output "App start failed, not found in process list" | tee -a "$LOGFILE"  
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查adb recovery状态
# parameter:     无
# ---------------------------------------------------------------------------
recovery_state(){
    local attempt=1
    local max_attempts=5
    local adb_recovery_output=""
    while [ $attempt -lt $max_attempts ]
    do
        print_output "Attempt $attempt: Checking adb recovery..."| tee -a "$LOGFILE"
        adb_recovery_output=$(adb devices | grep -E "recovery$")
        # 检查adb recovery结果
        if [ -n "$adb_recovery_output" ]; then
            print_output "adb recovery check pass,${adb_recovery_output} exist" | tee -a "${LOGFILE}"
            return 0
        else
            print_output "adb recovery check fail on attempt $attempt" | tee -a "${LOGFILE}"
        fi
        attempt=$((attempt + 1))
        sleep 20
    done

    print_output "adb recovery check fail after $max_attempts attempts" | tee -a "${LOGFILE}"
    return 1
}

# ---------------------------------------------------------------------------
# Description:   adb push速率
# parameter1:    PC资源路径
# parameter2:    测试机拷贝路径
# ---------------------------------------------------------------------------
check_push_rate(){
    # 计算文件大小
    local FILE_SIZE=$(wc -c < "$1" | awk '{print $1}')
    local FILE_SIZE_MB=$(echo "scale=2; $FILE_SIZE / 1024 / 1024" | bc -l)
    print_output "adb push file size :${FILE_SIZE_MB}MB" | tee -a "${RESULT_FILE}"

    # 记录拷贝时长
    local start_time=$(date +%s.%N)
    adb push "$1" "$2"
    local end_time=$(date +%s.%N)
    local diff_time=$(echo "$end_time - $start_time" | bc -l)
    print_output "adb push file time :${diff_time}s" | tee -a "${RESULT_FILE}"

    # 计算adb push速率
    local push_rate=$(echo "scale=2; $FILE_SIZE_MB / $diff_time" | bc -l)
    print_output "adb push rate: ${push_rate}MB/s" | tee -a "${RESULT_FILE}"
}

# ---------------------------------------------------------------------------
# Description:   adb pull速率
# parameter1:    测试机资源路径
# parameter2:    PC拷贝路径
# ---------------------------------------------------------------------------
check_pull_rate(){
    # 计算文件大小
    local FILE_SIZE=$(adb shell "wc -c < $1" | awk '{print $1}')
    local FILE_SIZE_MB=$(echo "scale=2; $FILE_SIZE / 1024 / 1024" | bc -l)
    print_output "adb pull file size :${FILE_SIZE_MB}MB" | tee -a "${RESULT_FILE}"

    # 记录拷贝时长
    local start_time=$(date +%s.%N)
    adb pull "$1" "$2"
    local end_time=$(date +%s.%N)
    local diff_time=$(echo "$end_time - $start_time" | bc -l)
    print_output "adb pull file time :${diff_time}s" | tee -a "${RESULT_FILE}"

    # 计算adb pull速率
    local pull_rate=$(echo "scale=2; $FILE_SIZE_MB / $diff_time" | bc -l)
    print_output "adb pull rate: ${pull_rate}MB/s" | tee -a "${RESULT_FILE}"
}

# ---------------------------------------------------------------------------
# Description:   检查USB充电状态
# parameter:     USB充电状态
# ---------------------------------------------------------------------------
usb_charge(){
    local usb_charge_state=$(adb shell dumpsys battery)
    if echo "$usb_charge_state"| grep "$1"; then
        print_output "usb charge state is $1" >> "$LOGFILE"
        return 0
    else
        print_output "usb charge state is not $1" >> "$LOGFILE"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   设置USB当前模式
# parameter:     USB模式
# ---------------------------------------------------------------------------
set_usb_mode(){
    local set_mode="$1"
    adb shell svc usb setFunctions "${set_mode}" true
    print_output "set usb mode is ${set_mode}" >> "$LOGFILE"
    sleep 15
}

# ---------------------------------------------------------------------------
# Description:   获取USB当前模式
# parameter:     无
# ---------------------------------------------------------------------------
get_usb_mode(){
    local get_mode=$(adb shell svc usb getFunctions 2>&1)
    print_output "get usb mode is ${get_mode}" >> "$LOGFILE"
    echo "$get_mode"
}

# ---------------------------------------------------------------------------
# Description:   检查USB模式是否正确设置
# parameter:     无
# ---------------------------------------------------------------------------
check_usb_mode(){
    local current_mode="$1"
    set_usb_mode "$1"
    # 判断USB模式是否设置成功
    if [ "$(get_usb_mode)" = "$current_mode" ]; then
        print_output "current usb mode is ${current_mode}" | tee -a "${LOGFILE}"
        print_output "check usb mode pass" | tee -a "${RESULT_FILE}"
        return 0
    else
        print_output "current usb mode is ${current_mode}" | tee -a "${LOGFILE}"
        print_output "check usb mode fail" | tee -a "${RESULT_FILE}"
        return 1
    fi
}

# ---------------------------------------------------------------------------
# Description:   检查对应的USB模式开关是否正常
# parameter:     USB模式
# ---------------------------------------------------------------------------
on_off_usb_mode(){
    local on_usb_mode="$1"
    local off_usb_mode="none"
    for ((i=1; i<=5; i++)); do
        # 开启USB模式
        if check_usb_mode "${on_usb_mode}"; then
            print_output "on $1 mode ${i} times pass" | tee -a "${RESULT_FILE}"
            # 关闭USB模式
            set_usb_mode "${off_usb_mode}"
        else
            print_output "on $1 mode ${i} times fail" | tee -a "${RESULT_FILE}"
            return 1
        fi
    done
}

# ---------------------------------------------------------------------------
# Description:   检查USB模式切换是否正常
# parameter:     USB模式
# ---------------------------------------------------------------------------
switch_usb_mode(){
    local usb_modes=("mtp" "ptp" "rndis" "midi" "none")
    local new_usb_mode=()
    # 其余usb模式
    for mode in "${usb_modes[@]}"; do
        if [[ "$mode" != "$1" ]];then
            new_usb_mode+=("$mode")
        fi
    done
    # 切换USB模式
    for ((i=1; i<=5; i++)); do
        # 开启USB模式
        if check_usb_mode "$1"; then
            print_output "switch $1 mode ${i} times pass" | tee -a "${RESULT_FILE}"
            # 切换到其他USB模式
            set_usb_mode "${new_usb_mode[$((RANDOM % 4))]}"
        else
            print_output "switch $1 mode ${i} times fail" | tee -a "${RESULT_FILE}"
            return 1
        fi
    done
}
