def __init__(self, device_id=""): """ 初始化,获取系统临时文件存储目录,定义匹配数字模式 """ self.utils = ADB(device_id) self.tempFile = tempfile.gettempdir() self.pattern = re.compile(r"\d+")
class Element(object): """ 通过元素定位 """ def __init__(self, device_id=""): """ 初始化,获取系统临时文件存储目录,定义匹配数字模式 """ self.utils = ADB(device_id) self.tempFile = tempfile.gettempdir() self.pattern = re.compile(r"\d+") def __uidump(self): """ 获取当前Activity的控件树 """ if int(self.utils.getSdkVersion()) >= 19: self.utils.shell("uiautomator dump --compressed /data/local/tmp/uidump.xml").wait() else: self.utils.shell("uiautomator dump /data/local/tmp/uidump.xml").wait() self.utils.adb("pull data/local/tmp/uidump.xml %s" %self.tempFile).wait() self.utils.shell("rm /data/local/tmp/uidump.xml").wait() def __element(self, attrib, name): """ 同属性单个元素,返回单个坐标元组,(x, y) :args: - attrib - node节点中某个属性 - name - node节点中某个属性对应的值 """ Xpoint = None Ypoint = None self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" %self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: #获取元素所占区域坐标[x, y][x, y] bounds = elem.attrib["bounds"] #通过正则获取坐标列表 coord = self.pattern.findall(bounds) #求取元素区域中心点坐标 Xpoint = (int(coord[2]) - int(coord[0])) / 2.0 + int(coord[0]) Ypoint = (int(coord[3]) - int(coord[1])) / 2.0 + int(coord[1]) break if Xpoint is None or Ypoint is None: raise Exception("Not found this element(%s) in current activity"%name) return (Xpoint, Ypoint) def __elements(self, attrib, name): """ 同属性多个元素,返回坐标元组列表,[(x1, y1), (x2, y2)] """ pointList = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" %self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: bounds = elem.attrib["bounds"] coord = self.pattern.findall(bounds) Xpoint = (int(coord[2]) - int(coord[0])) / 2.0 + int(coord[0]) Ypoint = (int(coord[3]) - int(coord[1])) / 2.0 + int(coord[1]) #将匹配的元素区域的中心点添加进pointList中 pointList.append((Xpoint, Ypoint)) return pointList def __bound(self, attrib, name): """ 同属性单个元素,返回单个坐标区域元组,(x1, y1, x2, y2) """ coord = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" %self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: bounds = elem.attrib["bounds"] coord = self.pattern.findall(bounds) if not coord: raise Exception("Not found this element(%s) in current activity"%name) return (int(coord[0]), int(coord[1]), int(coord[2]), int(coord[3])) def __bounds(self, attrib, name): """ 同属性多个元素,返回坐标区域列表,[(x1, y1, x2, y2), (x3, y3, x4, y4)] """ pointList = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" %self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: bounds = elem.attrib["bounds"] coord = self.pattern.findall(bounds) pointList.append((int(coord[0]), int(coord[1]), int(coord[2]), int(coord[3]))) return pointList def __checked(self, attrib, name): """ 返回布尔值列表 """ boolList = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" %self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: checked = elem.attrib["checked"] if checked == "true": boolList.append(True) else: boolList.append(False) return boolList def findElementByName(self, name): """ 通过元素名称定位单个元素 usage: findElementByName(u"设置") """ return self.__element("text", name) def findElementsByName(self, name): """ 通过元素名称定位多个相同text的元素 """ return self.__elements("text", name) def findElementByClass(self, className): """ 通过元素类名定位单个元素 usage: findElementByClass("android.widget.TextView") """ return self.__element("class", className) def findElementsByClass(self, className): """ 通过元素类名定位多个相同class的元素 """ return self.__elements("class", className) def findElementById(self, id): """ 通过元素的resource-id定位单个元素 usage: findElementsById("com.android.deskclock:id/imageview") """ return self.__element("resource-id",id) def findElementsById(self, id): """ 通过元素的resource-id定位多个相同id的元素 """ return self.__elements("resource-id",id) def findElementByContentDesc(self, contentDesc): """ 通过元素的content-desc定位单个元素 """ return self.__element("content-desc", contentDesc) def findElementsByContentDesc(self, contentDesc): """ 通过元素的content-desc定位多个相同的元素 """ return self.__elements("content-desc", contentDesc) def getElementBoundByName(self, name): """ 通过元素名称获取单个元素的区域 """ return self.__bound("text", name) def getElementBoundsByName(self, name): """ 通过元素名称获取多个相同text元素的区域 """ return self.__bounds("text", name) def getElementBoundByClass(self, className): """ 通过元素类名获取单个元素的区域 """ return self.__bound("class", className) def getElementBoundsByClass(self, className): """ 通过元素类名获取多个相同class元素的区域 """ return self.__bounds("class", className) def getElementBoundByContentDesc(self, contentDesc): """ 通过元素content-desc获取单个元素的区域 """ return self.__bound("content-desc", contentDesc) def getElementBoundsByContentDesc(self, contentDesc): """ 通过元素content-desc获取多个相同元素的区域 """ return self.__bounds("content-desc", contentDesc) def getElementBoundById(self, id): """ 通过元素id获取单个元素的区域 """ return self.__bound("resource-id", id) def getElementBoundsById(self, id): """ 通过元素id获取多个相同resource-id元素的区域 """ return self.__bounds("resource-id", id) def isElementsCheckedByName(self, name): """ 通过元素名称判断checked的布尔值,返回布尔值列表 """ return self.__checked("text", name) def isElementsCheckedById(self, id): """ 通过元素id判断checked的布尔值,返回布尔值列表 """ return self.__checked("resource-id", id) def isElementsCheckedByClass(self, className): """ 通过元素类名判断checked的布尔值,返回布尔值列表 """ return self.__checked("class", className)
def getElementBoundsById(self, id): """ 通过元素id获取多个相同resource-id元素的区域 """ return self.__bounds("resource-id", id) def isElementsCheckedByName(self, name): """ 通过元素名称判断checked的布尔值,返回布尔值列表 """ return self.__checked("text", name) def isElementsCheckedById(self, id): """ 通过元素id判断checked的布尔值,返回布尔值列表 """ return self.__checked("resource-id", id) def isElementsCheckedByClass(self, className): """ 通过元素类名判断checked的布尔值,返回布尔值列表 """ return self.__checked("class", className) if __name__ == "__main__": import time element = Element() adb = ADB() print adb.getAndroidVersion() adb.touch(element.findElementByContentDesc("Shutter button"))
def __init__(self, device_id=""): """ 初始化,获取系统临时文件存放目录 """ self.utils = ADB(device_id) self.tempFile = tempfile.gettempdir()
class ImageUtils(object): def __init__(self, device_id=""): """ 初始化,获取系统临时文件存放目录 """ self.utils = ADB(device_id) self.tempFile = tempfile.gettempdir() def screenShot(self): """ 截取设备屏幕 """ self.utils.shell("screencap -p /data/local/tmp/temp.png").wait() self.utils.adb("pull /data/local/tmp/iuniTemp.png %s" %self.tempFile).wait() return self def writeToFile(self, dirPath, imageName, form = "png"): """ 将截屏文件写到本地 usage: screenShot().writeToFile("d:\\screen", "image") """ if not os.path.isdir(dirPath): os.makedirs(dirPath) shutil.copyfile(PATH("%s/temp.png" %self.tempFile), PATH("%s/%s.%s" %(dirPath, imageName, form))) self.utils.shell("rm /data/local/tmp/temp.png") def loadImage(self, imageName): """ 加载本地图片 usage: lodImage("d:\\screen\\image.png") """ if os.path.isfile(imageName): load = Image.open(imageName) return load else: print "image is not exist" def subImage(self, box): """ 截取指定像素区域的图片 usage: box = (100, 100, 600, 600) screenShot().subImage(box) """ image = Image.open(PATH("%s/temp.png" %self.tempFile)) newImage = image.crop(box) newImage.save(PATH("%s/temp.png" %self.tempFile)) return self #http://testerhome.com/topics/202 def sameAs(self,loadImage): """ 比较两张截图的相似度,完全相似返回True usage: load = loadImage("d:\\screen\\image.png") screen().subImage(100, 100, 400, 400).sameAs(load) """ import math import operator image1 = Image.open(PATH("%s/temp.png" %self.tempFile)) image2 = loadImage histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt(reduce(operator.add, list(map(lambda a,b: (a-b)**2, \ histogram1, histogram2)))/len(histogram1)) if differ == 0: return True else: return False
class Element(object): """ 通过元素定位 """ def __init__(self, device_id=""): """ 初始化,获取系统临时文件存储目录,定义匹配数字模式 """ self.utils = ADB(device_id) self.tempFile = tempfile.gettempdir() self.pattern = re.compile(r"\d+") def __uidump(self): """ 获取当前Activity的控件树 """ if int(self.utils.getSdkVersion()) >= 19: self.utils.shell( "uiautomator dump --compressed /data/local/tmp/uidump.xml" ).wait() else: self.utils.shell( "uiautomator dump /data/local/tmp/uidump.xml").wait() self.utils.adb("pull data/local/tmp/uidump.xml %s" % self.tempFile).wait() self.utils.shell("rm /data/local/tmp/uidump.xml").wait() def __element(self, attrib, name): """ 同属性单个元素,返回单个坐标元组,(x, y) :args: - attrib - node节点中某个属性 - name - node节点中某个属性对应的值 """ Xpoint = None Ypoint = None self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" % self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: #获取元素所占区域坐标[x, y][x, y] bounds = elem.attrib["bounds"] #通过正则获取坐标列表 coord = self.pattern.findall(bounds) #求取元素区域中心点坐标 Xpoint = (int(coord[2]) - int(coord[0])) / 2.0 + int(coord[0]) Ypoint = (int(coord[3]) - int(coord[1])) / 2.0 + int(coord[1]) break if Xpoint is None or Ypoint is None: raise Exception("Not found this element(%s) in current activity" % name) return (Xpoint, Ypoint) def __elements(self, attrib, name): """ 同属性多个元素,返回坐标元组列表,[(x1, y1), (x2, y2)] """ pointList = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" % self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: bounds = elem.attrib["bounds"] coord = self.pattern.findall(bounds) Xpoint = (int(coord[2]) - int(coord[0])) / 2.0 + int(coord[0]) Ypoint = (int(coord[3]) - int(coord[1])) / 2.0 + int(coord[1]) #将匹配的元素区域的中心点添加进pointList中 pointList.append((Xpoint, Ypoint)) return pointList def __bound(self, attrib, name): """ 同属性单个元素,返回单个坐标区域元组,(x1, y1, x2, y2) """ coord = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" % self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: bounds = elem.attrib["bounds"] coord = self.pattern.findall(bounds) if not coord: raise Exception("Not found this element(%s) in current activity" % name) return (int(coord[0]), int(coord[1]), int(coord[2]), int(coord[3])) def __bounds(self, attrib, name): """ 同属性多个元素,返回坐标区域列表,[(x1, y1, x2, y2), (x3, y3, x4, y4)] """ pointList = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" % self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: bounds = elem.attrib["bounds"] coord = self.pattern.findall(bounds) pointList.append((int(coord[0]), int(coord[1]), int(coord[2]), int(coord[3]))) return pointList def __checked(self, attrib, name): """ 返回布尔值列表 """ boolList = [] self.__uidump() tree = ET.ElementTree(file=PATH("%s/uidump.xml" % self.tempFile)) treeIter = tree.iter(tag="node") for elem in treeIter: if elem.attrib[attrib] == name: checked = elem.attrib["checked"] if checked == "true": boolList.append(True) else: boolList.append(False) return boolList def findElementByName(self, name): """ 通过元素名称定位单个元素 usage: findElementByName(u"设置") """ return self.__element("text", name) def findElementsByName(self, name): """ 通过元素名称定位多个相同text的元素 """ return self.__elements("text", name) def findElementByClass(self, className): """ 通过元素类名定位单个元素 usage: findElementByClass("android.widget.TextView") """ return self.__element("class", className) def findElementsByClass(self, className): """ 通过元素类名定位多个相同class的元素 """ return self.__elements("class", className) def findElementById(self, id): """ 通过元素的resource-id定位单个元素 usage: findElementsById("com.android.deskclock:id/imageview") """ return self.__element("resource-id", id) def findElementsById(self, id): """ 通过元素的resource-id定位多个相同id的元素 """ return self.__elements("resource-id", id) def findElementByContentDesc(self, contentDesc): """ 通过元素的content-desc定位单个元素 """ return self.__element("content-desc", contentDesc) def findElementsByContentDesc(self, contentDesc): """ 通过元素的content-desc定位多个相同的元素 """ return self.__elements("content-desc", contentDesc) def getElementBoundByName(self, name): """ 通过元素名称获取单个元素的区域 """ return self.__bound("text", name) def getElementBoundsByName(self, name): """ 通过元素名称获取多个相同text元素的区域 """ return self.__bounds("text", name) def getElementBoundByClass(self, className): """ 通过元素类名获取单个元素的区域 """ return self.__bound("class", className) def getElementBoundsByClass(self, className): """ 通过元素类名获取多个相同class元素的区域 """ return self.__bounds("class", className) def getElementBoundByContentDesc(self, contentDesc): """ 通过元素content-desc获取单个元素的区域 """ return self.__bound("content-desc", contentDesc) def getElementBoundsByContentDesc(self, contentDesc): """ 通过元素content-desc获取多个相同元素的区域 """ return self.__bounds("content-desc", contentDesc) def getElementBoundById(self, id): """ 通过元素id获取单个元素的区域 """ return self.__bound("resource-id", id) def getElementBoundsById(self, id): """ 通过元素id获取多个相同resource-id元素的区域 """ return self.__bounds("resource-id", id) def isElementsCheckedByName(self, name): """ 通过元素名称判断checked的布尔值,返回布尔值列表 """ return self.__checked("text", name) def isElementsCheckedById(self, id): """ 通过元素id判断checked的布尔值,返回布尔值列表 """ return self.__checked("resource-id", id) def isElementsCheckedByClass(self, className): """ 通过元素类名判断checked的布尔值,返回布尔值列表 """ return self.__checked("class", className)
""" 通过元素id获取多个相同resource-id元素的区域 """ return self.__bounds("resource-id", id) def isElementsCheckedByName(self, name): """ 通过元素名称判断checked的布尔值,返回布尔值列表 """ return self.__checked("text", name) def isElementsCheckedById(self, id): """ 通过元素id判断checked的布尔值,返回布尔值列表 """ return self.__checked("resource-id", id) def isElementsCheckedByClass(self, className): """ 通过元素类名判断checked的布尔值,返回布尔值列表 """ return self.__checked("class", className) if __name__ == "__main__": import time element = Element() adb = ADB() print adb.getAndroidVersion() adb.touch(element.findElementByContentDesc("Shutter button"))
class ImageUtils(object): def __init__(self, device_id=""): """ 初始化,获取系统临时文件存放目录 """ self.utils = ADB(device_id) self.tempFile = tempfile.gettempdir() def screenShot(self): """ 截取设备屏幕 """ self.utils.shell("screencap -p /data/local/tmp/temp.png").wait() self.utils.adb("pull /data/local/tmp/iuniTemp.png %s" % self.tempFile).wait() return self def writeToFile(self, dirPath, imageName, form="png"): """ 将截屏文件写到本地 usage: screenShot().writeToFile("d:\\screen", "image") """ if not os.path.isdir(dirPath): os.makedirs(dirPath) shutil.copyfile(PATH("%s/temp.png" % self.tempFile), PATH("%s/%s.%s" % (dirPath, imageName, form))) self.utils.shell("rm /data/local/tmp/temp.png") def loadImage(self, imageName): """ 加载本地图片 usage: lodImage("d:\\screen\\image.png") """ if os.path.isfile(imageName): load = Image.open(imageName) return load else: print "image is not exist" def subImage(self, box): """ 截取指定像素区域的图片 usage: box = (100, 100, 600, 600) screenShot().subImage(box) """ image = Image.open(PATH("%s/temp.png" % self.tempFile)) newImage = image.crop(box) newImage.save(PATH("%s/temp.png" % self.tempFile)) return self #http://testerhome.com/topics/202 def sameAs(self, loadImage): """ 比较两张截图的相似度,完全相似返回True usage: load = loadImage("d:\\screen\\image.png") screen().subImage(100, 100, 400, 400).sameAs(load) """ import math import operator image1 = Image.open(PATH("%s/temp.png" % self.tempFile)) image2 = loadImage histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt(reduce(operator.add, list(map(lambda a,b: (a-b)**2, \ histogram1, histogram2)))/len(histogram1)) if differ == 0: return True else: return False