# -*- coding: utf-8 -*-
import os
import traceback
from time import sleep, time
import aircv as ac
from robot.libraries.BuiltIn import BuiltIn
global CUSTOMER_LIBRARY_NAME
CUSTOMER_LIBRARY_NAME = 'AppiumLibrary'
[docs]class AircvLibrary(object):
""" Wrapper Keywords for RobotFramework to click mobile screen, based on opencv & aircv.
"""
def __init__(self):
self.TH = 0.85 # THRESHOLD
self._screen = ""
self._timeout = 10
self.img_path = ""
self.output_dir = ""
self._mobilelib = ""
self._driver = ""
"""only can achieve BuiltIn().get_variables() at running time"""
# sys_variables = BuiltIn().get_variables()
# self.output_dir = os.path.abspath(sys_variables['${OUTPUTDIR}'])
def _get_appium_handle(self):
if not self._mobilelib:
self._mobilelib = BuiltIn().get_library_instance(CUSTOMER_LIBRARY_NAME)
if not self._driver:
self._driver = self._mobilelib._current_application()
def _capture_background(self, filename="screen.png"):
"""
:param filename: the background screen
:return: None
"""
self._screen = os.path.join(self.output_dir, filename)
self._mobilelib.capture_page_screenshot_without_html_log(os.path.join(self.output_dir, self._screen))
def _prepare(self):
""" update background screen
"""
self._get_appium_handle()
if not self.output_dir:
sys_variables = BuiltIn().get_variables()
self.output_dir = os.path.abspath(sys_variables['${OUTPUTDIR}'])
if os.path.isfile(self._screen):
os.remove(self._screen)
self._capture_background()
start_time = time()
while time() - start_time < self._timeout:
if os.path.isfile(self._screen):
return
sleep(0.2)
continue
self._mobilelib._info("[>>>]:Capture Background failed")
def mobile_image_threshold(self, threshold):
self.TH = float(threshold)
[docs] def mobile_image_set_timeout(self, time_num):
"""
:param time_num: wait in N secs to capture background screen
:return: None
"""
self._timeout = time_num
[docs] def mobile_image_set_path(self, path='None'):
"""
:param path: set the target image path
:return: None
"""
self.img_path = path
[docs] def mobile_image_listdir(self):
"""show the target image directory's content
"""
self._mobilelib._info("*" * 6)
if self.img_path:
self._mobilelib._info(self.img_path)
self._mobilelib._info('-' * 6)
content = os.listdir(self.img_path)
if content.__len__() > 0:
for item in content:
self._mobilelib._info(item)
else:
self._mobilelib._info("[>>>]:None Image")
else:
self._mobilelib._info("[>>>]:Image Path is NONE")
self._mobilelib._info("*" * 6)
def _image_click(self, target, index=1):
"""
:param target: the target image that should be clicked
:param index: select the N-th element
:return: match info
"""
index = int(index)
self._prepare()
if self.img_path:
target = os.path.join(self.img_path, target)
else:
self._mobilelib._info("[>>>] img path not set")
im_source = ac.imread(self._screen.decode('utf-8').encode('gbk'))
im_search = ac.imread(target.decode('utf-8').encode('gbk'))
result = ac.find_all_template(im_source, im_search, self.TH)
if index == 0:
index = len(result) - 1
else:
index -= 1
re = result[index]
self._mobilelib._info(re)
self._mobilelib.click_a_point(re['result'][0], re['result'][1])
return re
[docs] def mobile_click_image(self, target, index=1):
"""
:param target: the target image that should be clicked
:param index: select the N-th element; 0 -> the last one
:return: match info
"""
return self._image_click(target, index)
[docs] def mobile_click_in(self, parent_image, sub_image):
""" click the sub image in the parent image
"""
return self._parse_image_in(parent_image, sub_image, 'click')
[docs] def mobile_get_image_location_in(self, parent_image, sub_image):
""" get the sub image's coordinate which in the parent image
"""
return self._parse_image_in(parent_image, sub_image, 'coordinate')
def _parse_image_in(self, parent_image, sub_image, phase_type='click'):
print 'Here is sub search img'
self._prepare()
if self.img_path:
parent_image = os.path.join(self.img_path, parent_image)
sub_image = os.path.join(self.img_path, sub_image)
else:
self._mobilelib._info("[>>>] img path not set")
im_source = ac.imread(self._screen.decode('utf-8').encode('gbk'))
im_parent = ac.imread(parent_image.decode('utf-8').encode('gbk'))
im_sub = ac.imread(sub_image.decode('utf-8').encode('gbk'))
intermediate = ac.find_template(im_source, im_parent, self.TH)
in_rect = intermediate['rectangle']
result = ac.find_all_template(im_source, im_sub, self.TH)
for i in range(0, len(result), 1):
result_rect = result[i]['rectangle']
# only cmp left-top && right-down 's coordinate
# rectangle[0~1]: left-top,left-down
# rectangle[2~3]: right-top,right-down
if self._coordinate_cmp(result_rect[0], in_rect[0]): # left-top
if self._coordinate_cmp(in_rect[3], result_rect[3]): # right-down
try:
if 'click' in phase_type:
self._mobilelib.click_a_point(result[i]['result'][0], result[i]['result'][1])
elif 'coordinate' in phase_type:
return result[i]['result'][0], result[i]['result'][1]
except Exception, e:
print '[xxx]: %s ' % traceback.format_exc()
# Todo : return valid value
return -1
[docs] def mobile_get_images_num(self, target):
""" get sum of the image in current screen
"""
return self._parse_images(target)
[docs] def mobile_get_images_location(self, target, index=1):
""" get the N-th image's coordinate in current screen
"""
return self._parse_images(target, index, 'location')
def _parse_images(self, target, index=1, parse_type='num'):
"""[get the N-th image's coordinate] OR [the sum of the image]
:param target: the target image that should be clicked
:param index: select the N-th element; 0 -> the last one
:return: the target Element's location:<x,y>
"""
self._prepare()
index = int(index)
if self.img_path:
target = os.path.join(self.img_path, target)
else:
self._mobilelib._info("[>>>] img path not set")
im_source = ac.imread(self._screen.decode('utf-8').encode('gbk'))
im_search = ac.imread(target.decode('utf-8').encode('gbk'))
result = ac.find_all_template(im_source, im_search, self.TH)
if 'num' in parse_type:
return len(result)
elif 'location' in parse_type:
if index == 0:
index = len(result) - 1
else:
index -= 1
re = result[index]
self._mobilelib._info(re)
return re['result'][0], re['result'][1]
[docs] def mobile_screen_should_contain(self, target):
"""assert current screen should contain target image
"""
self._prepare()
im_source = ac.imread(self._screen)
im_search = ac.imread(target)
re = ac.find_template(im_source, im_search, self.TH)
if re:
return True
return False
[docs] def mobile_screen_should_not_contain(self, target):
"""assert current screen should NOT contain target image
"""
if self.mobile_screen_should_contain(target):
return False
return True
def _coordinate_cmp(self, a, b):
"""
@param a: (x0,y0)
@param b: (x1,y1)
@return: (x0>=x1) && (y0>=y1)? True:False
"""
if len(a) == len(b):
for i in range(0, len(a), 1):
if a[i] < b[i]:
return False
else:
return False
return True