Skip to content
This repository has been archived by the owner on Mar 1, 2019. It is now read-only.

Commit

Permalink
add code generate insert code support
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Mar 15, 2016
1 parent 1240e3d commit 3ce5885
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 204 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,9 @@ d.stop_app(package_name)

3. 是否可以在模拟器上运行自动测试

测试后,发现是可以的。我直接用了当前市场上最流行的[海马玩 版本0.9.0 Beta](http://www.droid4x.cn/) 安装完之后使用 `adb connect 127.0.0.1:26944` 连接上,之后的操作就跟普通的手机一样了。_注: 根据海马玩版本的不同,端口可能也不一定一样_
测试后,发现是可以的。我直接用了当前市场上最流行的[海马玩 版本0.9.0 Beta](http://dl.haima.me/download/D4XU/win/0.9.0/Setup.exe) 安装完之后使用 `adb connect 127.0.0.1:26944` 连接上,之后的操作就跟普通的手机一样了。_注: 根据海马玩版本的不同,端口可能也不一定一样_

海马玩监听的端口26944是本机的如果需要测试脚本运行在远程,也是有办法。用个简单的tcp转发到0.0.0.0就好了。方法有很多,微软自带的[netsh](https://technet.microsoft.com/en-us/library/cc776297(WS.10).aspx#BKMK_1) 或者直接参考目录下的 [scripts/simple-tcp-proxy.py](scripts/simple-tcp-proxy.py) 用代码实现
海马玩监听的端口是本机的26944,如果需要测试脚本运行在远程,用tcp转发到0.0.0.0就好了。方法有很多,微软自带的[netsh](https://technet.microsoft.com/en-us/library/cc776297(WS.10).aspx#BKMK_1) 或者直接参考目录下的 [scripts/simple-tcp-proxy.py](scripts/simple-tcp-proxy.py) 用代码实现

## 代码导读
`connect` 函数负责根据平台返回相应的类(AndroidDevice or IOSDevice)
Expand Down
172 changes: 0 additions & 172 deletions atx/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,175 +21,3 @@ def main():

if __name__ == '__main__':
main()

# Point = collections.namedtuple('Point', ['x', 'y'])

# def cv2_to_pil(image):
# img_str = cv2.imencode('.png', image)[1].tostring()
# return Image.open(StringIO(img_str))


# def make_mouse_callback(imgs, ref_pt):
# # initialize the list of reference points and boolean indicating
# # whether cropping is being performed or not
# cropping = [False]

# def _click_and_crop(event, x, y, flags, param):
# # grab references to the global variables
# # global ref_pt, cropping

# # if the left mouse button was clicked, record the starting
# # (x, y) coordinates and indicate that cropping is being
# # performed
# if event == cv2.EVENT_LBUTTONDOWN:
# ref_pt[0] = Point(x, y)
# cropping[0] = True

# # check to see if the left mouse button was released
# elif event == cv2.EVENT_LBUTTONUP:
# # record the ending (x, y) coordinates and indicate that
# # the cropping operation is finished
# ref_pt[1] = Point(x, y)
# cropping[0] = False

# # draw a rectangle around the region of interest
# imgs[1] = image = imgs[0].copy()
# cv2.rectangle(image, ref_pt[0], ref_pt[1], (0, 255, 0), 2)
# cv2.imshow("image", image)
# elif event == cv2.EVENT_MOUSEMOVE and cropping[0]:
# img2 = imgs[0].copy()
# cv2.rectangle(img2, ref_pt[0], (x, y), (0, 255, 0), 2)
# imgs[1] = image = img2
# cv2.imshow("image", image)
# return _click_and_crop

# def interactive_save(image): #, save_to=None):
# imgpil = cv2_to_pil(image)
# #img_str = cv2.imencode('.png', image)[1].tostring()
# #imgpil = Image.open(StringIO(img_str))

# root = Tk.Tk()
# root.geometry('{}x{}'.format(400, 400))
# imgtk = ImageTk.PhotoImage(image=imgpil)
# panel = Tk.Label(root, image=imgtk) #.pack()
# panel.pack(side="bottom", fill="both", expand="yes")

# # if not save_to:
# save_to = tkSimpleDialog.askstring("Save cropped image", "Enter filename")
# if save_to:
# if save_to.find('.') == -1:
# save_to += '.png'
# print 'Save to:', save_to
# cv2.imwrite(save_to, image)
# root.destroy()

# def long_task(secs=2):
# import time
# time.sleep(secs)
# print 'hello'

# def worker(que):
# while True:
# (func, args, kwargs) = que.get()
# try:
# func(*args, **kwargs)
# except Exception as e:
# print e
# finally:
# que.task_done()

# class SimpleIDE():
# def __init__(self):
# self.tk = Tk.Tk()
# self.tk.geometry('{}x{}'.format(400, 400))

# frame = Tk.Frame(self.tk, height=40, bg='#ddd')
# frame.pack_propagate(0)
# frame.pack(fill=Tk.X)

# self.btn_quit = Tk.Button(
# frame, text='Quit', command=frame.quit)
# self.btn_quit.pack(side=Tk.RIGHT)
# self.btn_hello = Tk.Button(
# frame, text='Hello', fg='red', command=self.say_hi)
# self.btn_hello.pack(side=Tk.LEFT)

# def say_hi(self):
# print 'Hi there, everyone!'

# def mainloop(self):
# self.tk.mainloop()
# try:
# self.tk.destroy()
# except:
# pass

# def simple_ide():
# que = Queue()
# que.put((long_task, (), {}))

# th = threading.Thread(name='worker', target=worker, args=(que,))
# th.daemon = True
# th.start()

# root = SimpleIDE()
# root.mainloop()
# # root.mainloop()
# # root.destroy()

# # btn_hello = Tk.Button(root, text="Hello!")
# #btn_hello.set_text("World")
# # btn_hello.pack()
# # root.mainloop()

# def main():
# # construct the argument parser and parse the arguments
# #simple_ide()
# ap = argparse.ArgumentParser()
# ap.add_argument("-s", "--serial", required=False, help="Android serialno")
# # ap.add_argument("-o", "--output", required=True, help="Output image file, ext must be png")
# args = vars(ap.parse_args())

# # simple_ide()
# # return

# d = atx.connect(args["serial"])
# origin = d.screenshot()
# origin = atx.imutils.from_pillow(origin)

# # load the image, clone it, and setup the mouse callback function
# # origin = cv2.imread(output)
# image = cv2.resize(origin, (0, 0), fx=0.5, fy=0.5)
# images = [image.copy(), image]
# ref_pt = [None, None]

# cv2.namedWindow("image")
# cv2.setMouseCallback("image", make_mouse_callback(images, ref_pt))

# while True:
# # display the image and wait for a keypress
# cv2.imshow("image", images[1])
# key = cv2.waitKey(1) & 0xFF

# # if the 'c' key is pressed, break from the loop
# if key == ord("r"):
# origin = d.screenshot()
# image = cv2.resize(origin, (0, 0), fx=0.5, fy=0.5)
# images[0] = image.copy()
# images[1] = image
# if key == ord("c"):
# if ref_pt[1] is None:
# continue
# (a, b) = ref_pt
# a = Point(a.x*2, a.y*2)
# b = Point(b.x*2, b.y*2)
# roi = origin[a.y:b.y, a.x:b.x]
# interactive_save(roi)
# elif key == ord("q"):
# break

# # close all open windows
# cv2.destroyAllWindows()

# if __name__ == '__main__':
# main()
30 changes: 9 additions & 21 deletions atx/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,22 @@ def __init__(self):
self.resolution = None

def sleep(self, secs):
"""Sleep some seconds
Args:
secs: float seconds
Returns:
self
"""
secs = int(secs)
for i in reversed(range(secs)):
sys.stdout.write('\r')
sys.stdout.write("sleep %ds, left %2ds" % (secs, i+1))
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\n")
return self

def exists(self, img, screen=None):
"""Check if image exists in screen, alias for match"""
Expand Down Expand Up @@ -301,9 +310,6 @@ def __init__(self, serialno=None, **kwargs):
self.minicap_rotation = None
self.screenshot_method = consts.SCREENSHOT_METHOD_AUTO
self.last_screenshot = None
# self._click_timeout = 20.0 # if icon not found in this time, then panic
# self._delay_after_click = 0.5 # when finished click, wait time
# self._loglock = threading.Lock()

@property
def wlan_ip(self):
Expand Down Expand Up @@ -521,24 +527,6 @@ def takeSnapshot(self, filename):
# except:
# return None

# def center(self):
# '''
# Center position
# '''
# w, h = self.shape()
# return w/2, h/2

# def drag(self, fpt, tpt, duration=0.5):
# '''
# Drag from one place to another place

# @param fpt,tpt: filename or position
# @param duration: float (duration of the event in seconds)
# '''
# fpt = self._val_to_point(fpt)
# tpt = self._val_to_point(tpt)
# return self.dev.drag(fpt, tpt, duration)

# def type(self, text):
# '''
# Input some text
Expand Down
85 changes: 76 additions & 9 deletions atx/tkgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,26 @@
import threading
import Tkinter as tk
import tkSimpleDialog
import tkFileDialog
from Queue import Queue

import atx
from PIL import Image, ImageTk


def insert_code(filename, code, save=True, marker='# ATX CODE'):
""" Auto append code """
content = ''
for line in open(filename, 'rb'):
if line.strip() == marker:
cnt = line.find(marker)
content += line[:cnt] + code
content += line
if save:
with open(filename, 'wb') as f:
f.write(content)
return content

class CropIDE(object):
def __init__(self, title='AirtestX Basic GUI', device=None):
self._device = device
Expand All @@ -31,13 +45,17 @@ def __init__(self, title='AirtestX Basic GUI', device=None):

self._refresh_text = tk.StringVar()
self._refresh_text.set("Refresh")
self._gencode_text = tk.StringVar()
self._attachfile_text = tk.StringVar()

self._init_items()
self._init_thread()

self._lastx = 0
self._lasty = 0
self._bounds = None # crop area
self._center = (0, 0) # center point, used for offset
self._center = (0, 0) # center point
self._offset = (0, 0) # offset to image center
self._size = (90, 90)
self._moved = False # click or click and move
self._color = 'red' # draw color
Expand All @@ -47,16 +65,29 @@ def __init__(self, title='AirtestX Basic GUI', device=None):

def _init_items(self):
root = self._root
root.resizable(0,0)
root.resizable(0, 0)

frm_control = tk.Frame(root)
frm_control.grid(column=0, row=0)
frm_control = tk.Frame(root, bg='#bbb')
frm_control.grid(column=0, row=0, padx=5, sticky=tk.NW)
frm_screen = tk.Frame(root, bg='#aaa')
frm_screen.grid(column=1, row=0)

tk.Button(frm_control, textvariable=self._refresh_text, command=self._redraw).grid(column=0, row=0, sticky=tk.W)
tk.Button(frm_control, text="Wakeup", command=self._device.wakeup).grid(column=0, row=1, sticky=tk.W)
tk.Button(frm_control, text="Save cropped", command=self._save_crop).grid(column=0, row=2, sticky=tk.W)
frm_ctrl_btns = tk.Frame(frm_control)
frm_ctrl_btns.grid(column=0, row=0, sticky=tk.W)
tk.Label(frm_control, text='-'*30).grid(column=0, row=1, sticky=tk.EW)
frm_ctrl_code = tk.Frame(frm_control)
frm_ctrl_code.grid(column=0, row=2, sticky=tk.EW)

tk.Button(frm_ctrl_btns, textvariable=self._refresh_text, command=self._redraw).grid(column=0, row=0, sticky=tk.W)
tk.Button(frm_ctrl_btns, text="Wakeup", command=self._device.wakeup).grid(column=0, row=1, sticky=tk.W)
tk.Button(frm_ctrl_btns, text="Save cropped", command=self._save_crop).grid(column=0, row=2, sticky=tk.W)

tk.Label(frm_ctrl_code, text='Generated code').grid(column=0, row=0, sticky=tk.W)
tk.Entry(frm_ctrl_code, textvariable=self._gencode_text, width=30).grid(column=0, row=1, sticky=tk.W)
tk.Button(frm_ctrl_code, text='Run code', command=self._run_code).grid(column=0, row=2, sticky=tk.W)
tk.Button(frm_ctrl_code, text='Insert and Run', command=self._run_and_insert).grid(column=0, row=3, sticky=tk.W)
tk.Button(frm_ctrl_code, text='Select File', command=self._run_selectfile).grid(column=0, row=4, sticky=tk.W)
tk.Label(frm_ctrl_code, textvariable=self._attachfile_text).grid(column=0, row=5, sticky=tk.W)

self.canvas = tk.Canvas(frm_screen, bg="blue", bd=0, highlightthickness=0, relief='ridge')
self.canvas.grid(column=0, row=0, padx=10, pady=10)
Expand Down Expand Up @@ -108,7 +139,30 @@ def _save_crop(self):
save_to += '.png'
print('Save to:', save_to)
self._image.crop(bounds).save(save_to)
# cv2.imwrite(save_to, image)
if self._offset == (0, 0):
self._gencode_text.set('click_image("%s")' % save_to)
else:
code = 'click_image(atx.ImageSelector("{name}", offset=({x}, {y})))'.format(
name=save_to, x=self._offset[0], y=self._offset[1])
self._gencode_text.set(code)

def _run_code(self):
code = 'self._device.'+self._gencode_text.get()
exec(code)

def _run_and_insert(self):
self._run_code()
filename = self._attachfile_text.get().strip()
code_snippet = self._gencode_text.get().strip()
if filename and code_snippet:
insert_code(filename, code_snippet+'\n')

def _run_selectfile(self):
filename = tkFileDialog.askopenfilename(**dict(
filetypes=[('All files', '.*'), ('Python', '.py')],
title='Select file'))
self._attachfile_text.set(filename)
print filename

def _redraw(self):
def foo():
Expand All @@ -118,10 +172,12 @@ def foo():

self._run_async(foo)
self._refresh_text.set("Refreshing ...")
self._bounds = None
self._reset()

def _reset(self):
self._bounds = None
self._offset = (0, 0)
self._center = (0, 0)
self.canvas.delete('boundsLine')
self.canvas.delete('clickPosition')

Expand All @@ -146,6 +202,17 @@ def _stroke_done(self, event):
x, y = c.canvasx(event.x), c.canvasy(event.y)
if self._moved:
x, y = (self._lastx+x)/2, (self._lasty+y)/2
self._offset = (0, 0)
elif self._bounds is None:
# print x, y
self._gencode_text.set('click(%d, %d)' % (x/self._ratio, y/self._ratio))
elif self._bounds is not None:
(x0, y0, x1, y1) = self._fix_bounds(self._bounds)
cx, cy = (x/self._ratio, y/self._ratio)
mx, my = (x0+x1)/2, (y0+y1)/2
self._offset = (offx, offy) = (cx-mx, cy-my)
self._gencode_text.set('offset=(%d, %d)' % (offx, offy))
# print self._bounds
self._center = (x, y) # rember position
self.tag_point(x, y)
self.canvas.itemconfigure('boundsLine', width=2)
Expand Down
1 change: 1 addition & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ monkey_record.py and monkey_playback from

### AndroidManifest.xml parser
python-androguard: <https://code.google.com/p/androguard/wiki/Usage#Androaxml>

0 comments on commit 3ce5885

Please sign in to comment.