Example #1
0
class FDevice(object):
    """ device object, and high level API """

    def __init__(self, device_id: str):
        assert is_device_connected(device_id), 'device {} not connected'.format(device_id)
        self.device_id: str = device_id

        self.mnc: MNCDevice = None
        self.player: ActionPlayer = None
        self.toolkit: PYAToolkit = None
        self.adb_utils: AdbDevice = None

        self.start()

    def start(self):
        """ start device """
        self.mnc = MNCDevice(self.device_id)
        self.player = ActionPlayer(self.device_id)
        self.toolkit = PYAToolkit(self.device_id)
        self.adb_utils = adb.device(serial=self.device_id)

        logger.debug('FDevice [{}] started'.format(self.device_id))

    def stop(self):
        """ stop device, and clean up """
        self.player and self.player.stop()

        self.mnc = None
        self.player = None
        self.toolkit = None

        logger.debug('FDevice [{}] stopped'.format(self.device_id))

    def reset(self):
        """ stop and restart device """
        self.stop()
        self.start()

    def screen_shot(self, save_to=None) -> str:
        """ screen shot and return its path (YOU SHOULD REMOVE IT BY YOURSELF!) """
        self.mnc.screen_shot()

        # save to specific place
        if save_to:
            if os.path.isdir(save_to):
                pic_name = '{}.png'.format(uuid.uuid1())
                final_path = os.path.join(save_to, pic_name)
            else:
                final_path = save_to
        # use tempfile
        else:
            temp_pic = tempfile.NamedTemporaryFile('w+', delete=False, suffix='.png')
            temp_pic_name = temp_pic.name
            final_path = temp_pic_name

        self.mnc.export_screen(final_path)
        logger.debug('Screenshot saved in [{}]'.format(final_path))
        return final_path

    def _find_target(self,
                     target_path: typing.Union[list, tuple],
                     save_pic: str = None) -> typing.Union[list, None]:
        """ base API, should not be directly used I think. find target pic in screen, and get widget list (or None) """
        pic_path = self.screen_shot()

        try:
            result_dict = detector.detect(target_path, pic_path)
            logger.info(f'detector result: {result_dict}')
            assert result_dict.values()

            result_list = list()
            for each_target_name, each_target_result in result_dict.items():
                # each target result may contains multi points
                for each_point in each_target_result:
                    each_target = FWidget(each_target_name, each_point)
                    result_list.append(each_target)

        except AssertionError as e:
            if config.STRICT_MODE:
                raise e

            # if not found, return None
            return None
        else:
            return result_list
        finally:
            # always clean temp pictures
            if save_pic:
                shutil.copy(pic_path, save_pic)
            os.remove(pic_path)

    # --- user API below ---
    def get_screen_size(self) -> tuple:
        """ (width, height) """
        return self.adb_utils.window_size()

    def get_widget_list(self, target_path: str, *args, **kwargs) -> typing.Union[list, None]:
        target_path = [target_path]

        target_result_list = self._find_target(target_path, *args, **kwargs)
        if not target_result_list:
            return None
        return target_result_list

    def get_widget(self, target_path: str, *args, **kwargs) -> typing.Union[FWidget, None]:
        widget_list = self.get_widget_list(target_path, *args, **kwargs)
        if not widget_list:
            return None
        return widget_list[0]

    def click(self, target_widget: FWidget):
        self.player.short_tap(target_widget.position)

    def long_click(self, target_widget: FWidget):
        self.player.long_tap(target_widget.position)

    def drag_and_drop(self, widget_1: FWidget, widget_2: FWidget):
        self.player.long_tap(widget_1.position, no_up=True)
        self.player.fast_swipe(widget_1.position, widget_2.position, no_down=True)

    def swipe_screen(self, start: str, end: str):
        """ use 'w', 's', 'a', 'd' and 'c' (center) to set the src and dst """
        width, height = self.get_screen_size()
        point_dict = {
            'w': (width / 2, 0),
            's': (width / 2, height),
            'a': (0, height / 2),
            'd': (width, height / 2),
            'c': (width / 2, height / 2),
        }
        assert (start in point_dict) and (end in point_dict), 'start and end should be selected from: [w, s, a, d, c]'
        self.player.fast_swipe(point_dict[start], point_dict[end])
Example #2
0
class FDevice(object):
    """ device object, and high level API """

    def __init__(self, device_id: str):
        assert is_device_connected(device_id), "device {} not connected".format(
            device_id
        )
        self.device_id: str = device_id

        self.mnc: typing.Optional[MNCDevice] = None
        self.player: typing.Optional[ActionPlayer] = None
        self.toolkit: typing.Optional[PYAToolkit] = None
        self.adb_utils: typing.Optional[AdbDevice] = None

        self.start()

    def start(self):
        """ start device """
        self.mnc = MNCDevice(self.device_id)
        self.player = ActionPlayer(self.device_id)
        self.toolkit = PYAToolkit(self.device_id)
        self.adb_utils = adb.device(serial=self.device_id)

        logger.debug("FDevice [{}] started".format(self.device_id))

    def stop(self):
        """ stop device, and clean up """
        self.player and self.player.stop()

        self.mnc = None
        self.player = None
        self.toolkit = None

        logger.debug("FDevice [{}] stopped".format(self.device_id))

    def reset(self):
        """ stop and restart device """
        self.stop()
        self.start()

    def screen_shot(self, save_to: str = None) -> str:
        """ screen shot and return its path (YOU SHOULD REMOVE IT BY YOURSELF!) """
        self.mnc.screen_shot()

        # save to specific place
        if save_to:
            if os.path.isdir(save_to):
                pic_name = "{}.png".format(uuid.uuid1())
                final_path = os.path.join(save_to, pic_name)
            else:
                final_path = save_to
        # use tempfile
        else:
            temp_pic = tempfile.NamedTemporaryFile("w+", delete=False, suffix=".png")
            temp_pic_name = temp_pic.name
            final_path = temp_pic_name

        self.mnc.export_screen(final_path)
        logger.debug("Screenshot saved in [{}]".format(final_path))
        return final_path

    def screen_shot_to_object(self) -> np.ndarray:
        """ screen shot and return numpy array (data saved in memory) """
        pic_path = self.screen_shot()
        # temp file will be automatically removed after usage
        data = cv2.imread(pic_path, cv2.COLOR_RGB2GRAY)
        os.remove(pic_path)
        return data

    def _find_target(
        self, target_path: typing.Union[list, tuple], save_pic: str = None
    ) -> typing.Union[list, None]:
        """ base API, should not be directly used I think. find target pic in screen, and get widget list (or None) """
        p = self.screen_shot_to_object()

        try:
            result_dict = detector.detect(target_path, p)
            logger.info(f"detector result: {result_dict}")
            assert result_dict.values()

            result_list = list()
            for each_target_name, each_target_result in result_dict.items():
                # each target result may contains multi points
                for each_point in each_target_result:
                    each_target = FWidget(each_target_name, each_point)
                    result_list.append(each_target)

        except AssertionError as e:
            if config.STRICT_MODE:
                raise e

            # if not found, return None
            return None
        else:
            return result_list
        finally:
            # always clean temp pictures
            if save_pic:
                cv2.imwrite(save_pic, p)

    # --- user API below ---
    def get_screen_size(self) -> tuple:
        """ (width, height) """
        return self.adb_utils.window_size()

    # alias
    get_width_and_height = get_screen_size

    def get_widget_list(
        self, target_path: str, *args, **kwargs
    ) -> typing.Union[list, None]:
        target_path = [target_path]

        target_result_list = self._find_target(target_path, *args, **kwargs)
        if not target_result_list:
            return None
        return target_result_list

    def get_widget(
        self, target_path: str, *args, **kwargs
    ) -> typing.Union[FWidget, None]:
        widget_list = self.get_widget_list(target_path, *args, **kwargs)
        if not widget_list:
            return None
        return widget_list[0]

    def click(self, target_widget: FWidget):
        self.player.short_tap(target_widget.position)

    def long_click(self, target_widget: FWidget):
        self.player.long_tap(target_widget.position)

    def drag_and_drop(self, widget_1: FWidget, widget_2: FWidget):
        self.player.long_tap(widget_1.position, no_up=True)
        self.player.fast_swipe(widget_1.position, widget_2.position, no_down=True)

    def swipe_screen(self, start: str, end: str):
        """ use 'w', 's', 'a', 'd' and 'c' (center) to set the src and dst """
        width, height = self.get_screen_size()
        point_dict = {
            "w": (width / 2, 0),
            "s": (width / 2, height),
            "a": (0, height / 2),
            "d": (width, height / 2),
            "c": (width / 2, height / 2),
        }
        assert (start in point_dict) and (
            end in point_dict
        ), "start and end should be selected from: [w, s, a, d, c]"
        self.player.fast_swipe(point_dict[start], point_dict[end])

    def get_ocr_text(self, **extra_args) -> list:
        """ need `findtext` and `tesserocr` installed. https://github.com/sirfz/tesserocr#installation """
        p = self.screen_shot_to_object()
        resp = detector.fi_client.analyse_with_object(
            p, "", engine=["ocr"], **extra_args
        )
        result_text_list = resp.ocr_engine.get_text()
        logger.debug(f"Detect text: {result_text_list}")
        return result_text_list

    def get_ssim(
        self, template_name_list: typing.Union[list, tuple], **extra_args
    ) -> typing.Dict[str, float]:
        p = self.screen_shot_to_object()
        template_name = ",".join(template_name_list)
        resp = detector.fi_client.analyse_with_object(
            p, template_name, engine=["sim"], **extra_args
        )

        ssim_dict = dict()
        for each_template_name in template_name_list:
            ssim = resp.sim_engine.get_sim(each_template_name)
            ssim_dict[each_template_name] = ssim
            logger.debug(f"Compared with {each_template_name}: {ssim}")
        return ssim_dict

    def get_interest_point_list(self, *args, **kwargs) -> typing.List[cv2.KeyPoint]:
        """ find key points with ORB engine """
        p = self.screen_shot_to_object()
        orb = cv2.ORB_create(*args, **kwargs)
        return orb.detect(p, None)
Example #3
0
class FDevice(object):
    def __init__(self, device_id: str):
        assert is_device_connected(device_id), 'device {} not connected'.format(device_id)
        self.device_id: str = device_id

        self.mnc: MNCDevice = None
        self.player: ActionPlayer = None
        self.toolkit: PYAToolkit = None

        self.start()

    def start(self):
        """ start device """
        self.mnc = MNCDevice(self.device_id)
        self.player = ActionPlayer(self.device_id)
        self.toolkit = PYAToolkit(self.device_id)

        logger.debug('FDevice [{}] started'.format(self.device_id))

    def stop(self):
        """ stop device, and clean up """
        self.player and self.player.stop()

        self.mnc = None
        self.player = None
        self.toolkit = None

        logger.debug('FDevice [{}] stopped'.format(self.device_id))

    def reset(self):
        """ stop and restart device """
        self.stop()
        self.start()

    def screen_shot(self, save_to=None) -> str:
        """ screen shot and return its path (YOU SHOULD REMOVE IT BY YOURSELF!) """
        self.mnc.screen_shot()

        # save to specific place
        if save_to:
            if os.path.isdir(save_to):
                pic_name = '{}.png'.format(uuid.uuid1())
                final_path = os.path.join(save_to, pic_name)
            else:
                final_path = save_to
        # use tempfile
        else:
            temp_pic = tempfile.NamedTemporaryFile('w+', delete=False, suffix='.png')
            temp_pic_name = temp_pic.name
            final_path = temp_pic_name

        self.mnc.export_screen(final_path)
        logger.debug('Screenshot saved in [{}]'.format(final_path))
        return final_path

    def find_target(self, target_path: str, save_pic: str = None) -> (list, tuple):
        """ find target pic in screen, and get its position (or None) """
        pic_path = self.screen_shot()
        result = detector.detect(target_path, pic_path)

        if save_pic:
            shutil.copy(pic_path, save_pic)
        os.remove(pic_path)

        try:
            target_point = detector.cal_location(result)
        except AssertionError:
            # if not found, return None
            return None
        return target_point

    def tap_target(self, target_path: str, duration: int = 100, save_pic: str = None):
        """ find target pic in screen, get its position, and tap it """
        target_point = self.find_target(target_path, save_pic=save_pic)
        assert target_point is not None, 'TARGET [{}] NOT FOUND IN SCREEN'.format(target_path)
        self.player.tap(target_point, duration=duration)