package net.northking.cctp.element.mobile.utils.phoneUtils;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;
import net.northking.cctp.element.core.IExecuteContext;
import net.northking.cctp.element.core.IStepTarget;
import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.element.core.exception.ParamMistakeException;
import net.northking.cctp.element.mobile.constants.ConfigPath;
import net.northking.cctp.element.mobile.constants.HzBankOcrCode;
import net.northking.cctp.element.mobile.constants.UsingType;
import net.northking.cctp.element.mobile.entity.Device;
import net.northking.cctp.element.mobile.utils.HttpUtils;
import net.northking.cctp.element.mobile.utils.RuntimeUtils;
import net.northking.cctp.element.mobile.utils.hzBank.HzBankOcrUtils;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 屏幕操作
 */
public class ScreenUtil {

    private static final Logger logger = LoggerFactory.getLogger(ScreenUtil.class);

    /**
     * <p>模拟手指向上、下、左、右四个方向滑动屏幕。</p>
     * <i>注意：</i>“滑屏时间”会对结果有影响，建议时间不要太短，正如手指滑屏一样，滑动太快，页面滚动持续很久。
     *
     * @param direction 滑动方向（up、down、left、right）
     */
    public static void standardSwipe(
            String direction,
            Integer duration,
            AppiumDriver<WebElement> driver
    ) {
        Integer width = ScreenUtil.getWindowWidth(driver);
        Integer height = ScreenUtil.getWindowHeight(driver);
        //默认左右滑屏滑动屏幕的4/5
        int size = width * 4 / 5;
        if ("up".equals(direction) || "down".equals(direction)) {
            size = height * 3 / 5;
        }
        standardSwipe(direction, duration, driver, size);
    }

    public static void standardSwipe(String direction,
                                     Integer duration,
                                     AppiumDriver<WebElement> driver,
                                     Integer size) {
        Integer width = ScreenUtil.getWindowWidth(driver);
        Integer height = ScreenUtil.getWindowHeight(driver);
        int x1, y1, x2, y2;
        if ("up".equalsIgnoreCase(direction)) {
            x1 = x2 = width / 2;
            y1 = height * 8 / 10;
            y2 = y1 - size;
        } else if ("down".equalsIgnoreCase(direction)) {
            x1 = x2 = width / 2;
            y1 = height * 2 / 10;
            y2 = y1 + size;
        } else if ("left".equalsIgnoreCase(direction)) {
            x1 = width * 9 / 10;
            x2 = x1 - size;
            y1 = y2 = height / 2;
        } else if ("right".equalsIgnoreCase(direction)) {
            x1 = width * 1 / 10;
            x2 = x1 + size;
            y1 = y2 = height / 2;
        } else {
            throw new ParamMistakeException("滑动方向仅支持：up、down、left、right");
        }
        int time = 0;
        if ((size - 500) > 0 && (size - 500) % 500 == 0) {
            time = (size - 500) / 500;
        } else if ((size - 500) > 0 && (size - 500) % 500 != 0){
            time = (size - 500) / 500 + 1;
        }
        try {
            long sum = duration + time * 1000L;
            new TouchAction(driver).press(PointOption.point(x1, y1))
                    .waitAction(WaitOptions.waitOptions(Duration.ofMillis(sum)))
                    .moveTo(PointOption.point(x2, y2))
                    .release().perform();
        } catch (WebDriverException e) {
            if (e instanceof NoSuchSessionException) {
                logger.warn("driver 失效了");
                throw e;
            } else {
                logger.warn("driver 抽风了。。。。。,重新来一次");
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException interruptedException) {
                    Thread.currentThread().interrupt();
                    logger.error("",e);
                }
                long sum = duration + time * 1000L;
                new TouchAction(driver).press(PointOption.point(x1, y1))
                        .waitAction(WaitOptions.waitOptions(Duration.ofMillis(sum)))
                        .moveTo(PointOption.point(x2, y2))
                        .release().perform();
            }

        }


    }


    public static Map<String,Integer> findAreaByImage(AppiumDriver<WebElement> driver, String imgBase64, Float faultRate, Integer timeout,
                                                      Integer waitTimeout, Boolean waitStatus, String swipe, Integer swipeCount, String findImageUrl,
                                                      IExecuteContext context){
        Map<String, Integer> resultMap = null;
        //是否等待界面稳定
        /*if (waitStatus) {
            try {
                wait.waitStable(driver, 3000, 30000);
            } catch (InterruptedException e) {
                logger.error("等待界面稳定出错",e);
            }
        }*/
        if (null == timeout || timeout < 0 || timeout > 120) {
            timeout = waitTimeout;
        }
        long start = System.currentTimeMillis();
        long end = System.currentTimeMillis();
        while (end - start < timeout * 1000) {  //查找时间
            resultMap = snapshotToFindImage(driver, imgBase64, faultRate,findImageUrl, context);
            if (null != resultMap) {
                logger.info("找到区域位置为:{}", JSON.toJSONString(resultMap));
                return resultMap;
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                logger.error("",e);
            }
            end = System.currentTimeMillis();
        }
        if (null == resultMap) {   //超过时间没找到
            logger.warn("指定时间内没有找到图片区域");
            if (!"0".equals(swipe)) {
                for (int i = 0; i < swipeCount; i++) {
                    logger.debug("尝试滑屏第{}次,滑屏方向：{}",i+1,swipe);
                    try {
                        standardSwipe(swipe,2000,driver);
                    } catch (Exception e) {
                        logger.error("滑屏出错：",e);
                        throw new ExecuteException("尝试滑屏出错");
                    }
                    start = System.currentTimeMillis();
                    end = System.currentTimeMillis();
                    while (end - start < timeout * 1000) {
                        resultMap = snapshotToFindImage(driver, imgBase64, faultRate,findImageUrl,context);
                        if (null != resultMap) {
                            logger.info("找到区域位置为:{}",JSON.toJSONString(resultMap));
                            return resultMap;
                        }
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            logger.error("",e);
                        }
                        end = System.currentTimeMillis();
                    }
                }
            } else {
                logger.debug("不尝试滑屏");
            }
        }
        return resultMap;
    }

    private static Map<String,Integer> snapshotToFindImage(AppiumDriver<WebElement> driver, String imgBase64, Float faultRate, String findImageUrl, IExecuteContext context){
        String sourceStr = null;
        File snapShotFile = null;
        try {
            if (driver instanceof AndroidDriver) {
                Device device = (Device) context.getContextVariable("device");
                if (null == device) {
                    throw new ParamMistakeException("设备信息不存在，请重新连接设备");
                }
                logger.info("查询的手机信息：{}", JSON.toJSONString(device));
                snapShotFile = getMobileScreenShot(device.getDeviceId(), device.getResolution());
            } else {
                snapShotFile = snapshot(driver);
            }
            if (null == snapShotFile) {
                throw new ExecuteException("当前页面截图失败，请确定当前页面是否支持截屏");
            }
            sourceStr = Base64.encode(snapShotFile);
        } catch (Exception e) {
            logger.error("手机截图失败",e);
            throw new ExecuteException("对比手机屏幕失败，请确保手机驱动连接是否正常");
        } finally {
            if (null != snapShotFile) {
                boolean delete = snapShotFile.delete();
                logger.info("删除文件snapShotFile：{}",delete);
            }
        }
        Map<String, Object> param = new HashMap<>();
        param.put("sourceImage", sourceStr);
        param.put("targetImage", imgBase64);
        param.put("matchingThreshold", faultRate);
        HttpEntity<Map> httpEntity = new HttpEntity<>(param,null);
        Map<String, Integer> resultPoint = null;
        try {
            URI uri = new URI(findImageUrl);
            Map body = HttpUtils.doPost(uri, httpEntity, Map.class);
            resultPoint = (Map<String, Integer>) body.get("data");
            return resultPoint;
        } catch (URISyntaxException e) {
            logger.error("找图像地址有误,地址：{}，错误:{}", findImageUrl, e);
            throw new ParamMistakeException(String.format("图像解析地址[%s]有误",findImageUrl));
        } catch (Exception e) {
            logger.error("请求图像解析服务失败,地址：{},参数:{},错误:{}", findImageUrl,JSON.toJSONString(param), e);
            throw new ParamMistakeException("请求图像解析服务失败,请检查图像解析服务是否可用");
        }
    }

    /**
     * android截屏
     * @param deviceId
     * @param resolution
     * @return
     */
    public static File getMobileScreenShot(String deviceId, String resolution) {
        String picPath = null;
        //获取分辨率
        String[] split = resolution.split("\\*");
        int isBigger = Integer.parseInt(split[0]) - Integer.parseInt(split[1]);
        String vm_size = "";
        if (isBigger > 0) {
            vm_size = split[1] + "x" + split[0];
        } else {
            vm_size = split[0] + "x" + split[1];
        }
        String fileName = "/sdcard/" + new Date().getTime() + ".jpg";
        String cmd = String.format("adb -s %s shell \"export CLASSPATH=/data/local/tmp/minicap.apk;app_process /system/bin  io.devicefarmer.minicap.Main -P %s@%s/0 -s > %s\"", deviceId, vm_size, vm_size, fileName);
        File cutFilePath = new File(System.getProperty("user.dir") + "/tempPic");
        if (!cutFilePath.exists()) {
            cutFilePath.mkdirs();
        }
        String localPath = cutFilePath.getAbsolutePath() + "/" + System.currentTimeMillis() + ".png";
        String pullCmd = String.format("adb -s %s pull %s %s", deviceId, fileName, localPath);
        String[] cmds = {"/bin/sh", "-c", cmd};
        String delCmd = String.format("adb -s %s shell rm %s", deviceId, fileName);
        Future future = Executors.newSingleThreadExecutor().submit(new Runnable() {
            public void run() {
                try {
                    Process process = Runtime.getRuntime().exec(cmds, null, null);
                    process.waitFor();
                    logger.info("截图命令：{}", cmd);
                    process.destroy();
                } catch (Exception e) {
                    logger.error("截图失败:", e);
                }
            }
        });
        try {
            future.get(5, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.error("截图超时:", e);
            throw new ExecuteException("截图超时");
        }
        try {
            String exec2 = RuntimeUtils.execComand(pullCmd, "");
            logger.debug("执行拉取图片命令：{},结果:{}", pullCmd,exec2);
        } catch (Exception e) {
            logger.error("拉取手机图片失败:{}",e);
            throw new ExecuteException("拉取手机图片失败");
        }

        try {
            String exec3 = RuntimeUtils.execComand(delCmd, "");
            logger.debug("执行删除手机截图图片命令：{},结果:{}", delCmd,exec3);
        } catch (Exception e) {
            logger.error("删除手机截图失败:{}",e);
        }
        File file = new File(localPath);
        return file;
    }

    /**
     * ios截屏
     * @param driver
     * @return
     */
    public static File snapshot(AppiumDriver<WebElement> driver) {
        File file = driver.getScreenshotAs(OutputType.FILE);
        logger.info("snapshot file:{}",file.getAbsolutePath());
        return file;
    }

    private static BufferedImage getImageInfo(String chart) {
        String base64Image = chart.replaceFirst("data:image/png;base64,", "");
        if (StringUtils.isNotEmpty(chart)) {
            try {
                byte[] decoder = new BASE64Decoder().decodeBuffer(base64Image);
                InputStream is = new ByteArrayInputStream(decoder);
                return ImageIO.read(is);
            } catch (IOException e) {
                logger.error("base64转换图片失败:", e);
                throw new ExecuteException("base64转换图片有误，请检查base64格式是否正确");
            }
        } else {
            throw new ExecuteException("base64内容不正确");
        }
    }


    public static String getCodeByOcr(IExecuteContext context,AppiumDriver<WebElement> driver, List<IStepTarget> targets, Integer timeout,boolean waitStatus){
        String imgBase64 = null;
        try {
            imgBase64 = ElementUtil.getOcrAreaBase64(context, driver, targets, timeout,waitStatus);
        } catch (NoSuchSessionException | ExecuteException | ParamMistakeException e) {
            throw e;
        } catch (Exception e) {
            logger.error("查找验证码区域失败",e);
            throw new ExecuteException("查找验证码区域失败");
        }
        if (null == imgBase64) {
            throw new ExecuteException("未截取到验证码区域");
        }
        if (CollectionUtils.isEmpty(targets)) {
            throw new ParamMistakeException("定位元素参数不能为空");
        }
        String usingType = targets.get(0).getUsing();
        if (UsingType.HZOCR.equalsIgnoreCase(usingType)) {
            String textByHzOcr;
            try {
                textByHzOcr = HzBankOcrUtils.getTextByHzOcr(imgBase64, context);
                return HzBankOcrUtils.getAllTextByData(textByHzOcr);
            } catch (Exception e) {
                logger.error("查找杭银ocr失败，原因为： {}", e);
                throw e;
            }
        } else {
            String ocrAddress = context.getProperty(ConfigPath.OCR_GET_CODE_ADDRESS_KEY);
            try {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                Map<String, Object> ocrParamMap = new HashMap<>();
                ocrParamMap.put("img_base64", imgBase64);
                HttpEntity<Map<String, Object>> ocrEntity = new HttpEntity<>(ocrParamMap, headers);
                String text = HttpUtils.doPost(new URI(ocrAddress), ocrEntity, String.class);
                logger.info("识别的图片代码text为：{}, 切割后为：{}", text, text.replace("\"", ""));
                return text.replace("\"", "");
            }catch (URISyntaxException e) {
                logger.error("ocr地址有误！===>{}",ocrAddress);
                throw new ParamMistakeException(String.format("ocr请求地址【%s】有误", ocrAddress));
            } catch (Exception e) {
                logger.error("请求ocr接口失败，接口地址：{}",ocrAddress,e);
                throw new ExecuteException("请求验证码识别接口失败，请查看验证码识别服务是否开启！");
            }
        }
    }

    public static String getTextByOcr(IExecuteContext context,AppiumDriver<WebElement> driver, IStepTarget target,boolean waitStatus){
        String imgBase64 = null;
        try {
            imgBase64 = ElementUtil.ocrFindCodeArea(target, driver, context);
        } catch (NoSuchSessionException | ExecuteException | ParamMistakeException e) {
            throw e;
        } catch (Exception e) {
            logger.error("查找验证码区域失败",e);
            throw new ExecuteException("查找验证码区域失败");
        }
        if (null == imgBase64) {
            throw new ExecuteException("未截取到验证码区域");
        }

        // 是否使用新版ocr
        boolean useNewOcr = Boolean.parseBoolean(context.getProperty(ConfigPath.USE_NEW_OCR));
        if (useNewOcr) {
            String ocrAddress = context.getProperty(ConfigPath.OCR_GET_ALL_TEXT_NUM_KEY);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            Map<String, Object> ocrParamMap = new HashMap<>();
            ocrParamMap.put("img_base64", imgBase64);
            ocrParamMap.put("targets", "");
            HttpEntity<Map> ocrEntity = new HttpEntity<>(ocrParamMap, headers);
            List ocrResultList = null;
            try {
                logger.info("传参：{}", JSON.toJSONString(ocrParamMap));
                ocrResultList = HttpUtils.doPost(ocrAddress, ocrEntity, List.class);
                logger.info("得到的ocr结果：{}", ocrResultList);
            } catch (Exception e) {
                logger.error("ocr失败", e);
            }
//            List<String> dataList = new ArrayList<>();
            StringJoiner dataList = new StringJoiner("");
            if (!CollectionUtils.isEmpty(ocrResultList)) {
                if (!CollectionUtils.isEmpty(ocrResultList)) {
                    for (Object o : ocrResultList) {
                        dataList.add(((Map) o).get("text") + "");
                    }
                }
            }
            return dataList.toString();
        } else {
            String ocrAddress = context.getProperty(ConfigPath.OCR_GET_TEXT_ADDRESS_KEY);
            try {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                HttpEntity<String> ocrEntity = new HttpEntity<>("\"" + imgBase64 + "\"", headers);
                JSONObject object = HttpUtils.doPost(new URI(ocrAddress), ocrEntity, JSONObject.class);
                JSONObject data = object.getJSONObject("data");
                String ocrText = null;
                if (data != null) {
                    ocrText = data.getString("ocrText");
                }
                logger.info("识别的图片代码为：{}", ocrText);
                return ocrText;
            } catch (URISyntaxException e) {
                logger.error("ocr地址有误！===>{}", ocrAddress);
                throw new ParamMistakeException(String.format("ocr请求地址【%s】有误", ocrAddress));
            } catch (Exception e) {
                logger.error("请求ocr接口失败，接口地址：{}", ocrAddress, e);
                throw new ExecuteException("请求验证码识别接口失败，请查看验证码识别服务是否开启！");
            }
        }
    }

    public static String getTextByHzOcr(IExecuteContext context,AppiumDriver<WebElement> driver, IStepTarget target,boolean waitStatus){
        String imgBase64 = null;
        try {
            imgBase64 = ElementUtil.ocrFindCodeArea(target, driver, context);
        } catch (NoSuchSessionException | ExecuteException | ParamMistakeException e) {
            throw e;
        } catch (Exception e) {
            logger.error("查找验证码区域失败",e);
            throw new ExecuteException("查找验证码区域失败");
        }
        if (null == imgBase64) {
            throw new ExecuteException("未截取到验证码区域");
        }
        String textByHzOcr;
        try {
            textByHzOcr = HzBankOcrUtils.getTextByHzOcr(imgBase64, context);
        } catch (Exception e) {
            logger.error("查找杭银ocr失败，原因为： {}", e);
            throw e;
        }
        return HzBankOcrUtils.getAllTextByData(textByHzOcr);
    }

    public static String getMoneyTextByOcr(IExecuteContext context,AppiumDriver<WebElement> driver, IStepTarget target,boolean waitStatus){
        String imgBase64 = null;
        try {
            imgBase64 = ElementUtil.ocrFindCodeArea(target, driver, context);
        } catch (NoSuchSessionException | ExecuteException | ParamMistakeException e) {
            throw e;
        } catch (Exception e) {
            logger.error("查找验证码区域失败",e);
            throw new ExecuteException("查找验证码区域失败");
        }
        if (null == imgBase64) {
            throw new ExecuteException("未截取到验证码区域");
        }
        String ocrAddress = context.getProperty(ConfigPath.OCR_GET_ALL_TEXT_NUM_KEY);
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            Map<String, Object> ocrParamMap = new HashMap<>();
            ocrParamMap.put("img_base64", imgBase64);
            ocrParamMap.put("targets", "");
            HttpEntity<Map> ocrEntity = new HttpEntity<>(ocrParamMap, headers);
            List ocrResultList = null;
            try {
                logger.info("传参：{}", JSON.toJSONString(ocrParamMap));
                ocrResultList = HttpUtils.doPost(ocrAddress, ocrEntity, List.class);
                logger.info("得到的ocr结果：{}", ocrResultList);
            } catch (Exception e) {
                logger.error("ocr失败", e);
            }
            StringJoiner dataList = new StringJoiner("");
            if (!CollectionUtils.isEmpty(ocrResultList)) {
                if (!CollectionUtils.isEmpty(ocrResultList)) {
                    for (Object o : ocrResultList) {
                        dataList.add(((Map) o).get("text") + "");
                    }
                }
            }
            return  dataList.toString();
        } catch (Exception e) {
            logger.error("请求ocr接口失败，接口地址：{}",ocrAddress,e);
            throw new ExecuteException("请求验证码识别接口失败，请查看验证码识别服务是否开启！");
        }
    }

    public static String getMoneyTextByHzOcr(IExecuteContext context,AppiumDriver<WebElement> driver, IStepTarget target,boolean waitStatus){
        String imgBase64 = null;
        try {
            imgBase64 = ElementUtil.ocrFindCodeArea(target, driver, context);
        } catch (NoSuchSessionException | ExecuteException | ParamMistakeException e) {
            throw e;
        } catch (Exception e) {
            logger.error("查找验证码区域失败",e);
            throw new ExecuteException("查找验证码区域失败");
        }
        if (null == imgBase64) {
            throw new ExecuteException("未截取到验证码区域");
        }
        String textByHzOcr;
        try {
            textByHzOcr = HzBankOcrUtils.getTextByHzOcr(imgBase64, context);
        } catch (Exception e) {
            logger.error("查找杭银ocr失败，原因为： {}", e);
            throw e;
        }
        return HzBankOcrUtils.getAllTextByData(textByHzOcr);
    }

    public static Integer getWindowWidth(AppiumDriver driver){
        Integer width = null;
        int time = 1;
        while (time <= 3 && width == null) {
            try {
                width = driver.manage().window().getSize().width;
            } catch (WebDriverException e) {
                logger.warn("获取屏幕宽时driver抽风了。。。。。。",e);
                if (e instanceof NoSuchSessionException) {
                    throw e;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException interruptedException) {
                    Thread.currentThread().interrupt();
                    logger.error("",e);
                }
            }
            time++;
        }
        if (null == width) {
            throw new ExecuteException("获取屏幕宽度失败");
        }
        return width;
    }

    public static Integer getWindowHeight(AppiumDriver driver){
        Integer height = null;
        int time = 1;
        while (time <= 3 && height == null) {
            try {
                height = driver.manage().window().getSize().height;
            } catch (WebDriverException e) {
                logger.warn("获取屏幕高时driver抽风了。。。。。。",e);
                if (e instanceof NoSuchSessionException) {
                    throw e;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException interruptedException) {
                    Thread.currentThread().interrupt();
                    logger.error("",e);
                }
            }
            time++;
        }
        if (null == height) {
            throw new ExecuteException("获取屏幕高度失败");
        }
        return height;
    }

    public static void pressAndSwipe(AppiumDriver driver,List<Map<String, Integer>> pointList,List<Integer> passingPoints){
        if (!CollectionUtils.isEmpty(passingPoints)) {
            Integer startIndex = passingPoints.get(0);
            Map<String, Integer> startPoint = pointList.get(startIndex - 1);
            PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
            Sequence sequence = new Sequence(finger, passingPoints.size()+2);
            sequence.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startPoint.get("x"), startPoint.get("y")));
            sequence.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
            for (int i=1;i<passingPoints.size();i++) {
                Integer index = passingPoints.get(i);
                Map<String, Integer> passPoint = pointList.get(index - 1);
                sequence.addAction(finger.createPointerMove(Duration.ofMillis(200), PointerInput.Origin.viewport(), passPoint.get("x"), passPoint.get("y")));
            }
            sequence.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
            driver.perform(Collections.singletonList(sequence));
        } else {
            logger.warn("没有滑动通过的坐标");
        }
        logger.info("滑动完毕");
    }
}
