Skip to content

Commit

Permalink
Optimized the logic of coordinate conversion when clicking and slidin…
Browse files Browse the repository at this point in the history
…g, the click speed is faster, but the ipad in the horizontal screen state is still slow. Improve test_ios use case, delete fake_minitouch
  • Loading branch information
yimelia committed Jan 28, 2021
1 parent 0660cc3 commit b377894
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 127 deletions.
8 changes: 5 additions & 3 deletions airtest/core/ios/constant.py
@@ -1,14 +1,12 @@
# -*- coding: utf-8 -*-
import os
import re
import sys
from enum import Enum
from airtest.utils.compat import decode_path
from wda import LANDSCAPE, PORTRAIT, LANDSCAPE_RIGHT, PORTRAIT_UPSIDEDOWN


THISPATH = decode_path(os.path.dirname(os.path.realpath(__file__)))
STATICPATH = os.path.join(THISPATH, "static")

DEFAULT_ADB_SERVER = ('127.0.0.1', 8100)
DEBUG = True
MINICAPLIB = os.path.join(STATICPATH, "minicap")
Expand Down Expand Up @@ -36,6 +34,10 @@ class ROTATION_MODE(Enum):
LANDSCAPE_RIGHT = 90
PORTRAIT_UPSIDEDOWN = 180

UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT = 90
UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN = 0


@classmethod
def _missing_(cls, value):
# default is PORTRAIT
Expand Down
63 changes: 0 additions & 63 deletions airtest/core/ios/fake_minitouch.py

This file was deleted.

123 changes: 65 additions & 58 deletions airtest/core/ios/ios.py
Expand Up @@ -11,7 +11,6 @@
from airtest.core.device import Device
from airtest.core.ios.constant import CAP_METHOD, TOUCH_METHOD, IME_METHOD, ROTATION_MODE, KEY_EVENTS
from airtest.core.ios.rotation import XYTransformer, RotationWatcher
from airtest.core.ios.fake_minitouch import fakeMiniTouch
from airtest.utils.logger import get_logger


Expand Down Expand Up @@ -96,15 +95,16 @@ def __init__(self, addr=DEFAULT_ADDR):

# record device's width
self._size = {'width': None, 'height': None}
self._touch_factor = 0.5
self._current_orientation = None
self._touch_factor = None
self._last_orientation = None
self._is_pad = None
self.defaultSession = None

# start up RotationWatcher with default session
self.rotation_watcher = RotationWatcher(self)
self._register_rotation_watcher()

# fake minitouch to simulate swipe
self.minitouch = fakeMiniTouch(self)
self.alert_watch_and_click = self.driver.alert.watch_and_click

@property
Expand All @@ -125,6 +125,32 @@ def _fetch_new_session(self):
"""
self.defaultSession = self.driver.session()

@property
def is_pad(self):
"""
Determine whether it is an ipad, if it is, in the case of horizontal screen + desktop,
the coordinates need to be switched to vertical screen coordinates to click correctly (WDA bug)
判断是否是ipad,如果是,在横屏+桌面的情况下,坐标需要切换成竖屏坐标才能正确点击(WDA的bug)
Returns:
"""
if self._is_pad is None:
info = self.driver.device_info()
self._is_pad = info["model"] == "iPad"
return self._is_pad

def _register_rotation_watcher(self):
"""
Register callbacks for Android and minicap when rotation of screen has changed
callback is called in another thread, so be careful about thread-safety
Returns:
None
"""
self.rotation_watcher.reg_callback(lambda x: setattr(self, "_current_orientation", x))

def window_size(self):
"""
return window size
Expand All @@ -141,17 +167,32 @@ def orientation(self):
return device oritantation status
in LANDSACPE POR
"""
z = self.driver._session_http.get('rotation').value.get('z')
return ROTATION_MODE(z).name
if not self._current_orientation:
z = self.driver._session_http.get('rotation').value.get('z')
self._current_orientation = ROTATION_MODE(z).name
return self._current_orientation

@property
def display_info(self):
if not self._size['width'] or not self._size['height']:
self.snapshot()
self._display_info()

return {'width': self._size['width'], 'height': self._size['height'], 'orientation': self.orientation,
'physical_width': self._size['width'], 'physical_height': self._size['height']}

def _display_info(self):
window_size = self.window_size()
scale = self.driver.scale
self._size['width'] = scale * window_size.width
self._size['height'] = scale * window_size.height
self._touch_factor = 1 / scale

@property
def touch_factor(self):
if not self._touch_factor:
self._display_info()
return self._touch_factor

def get_render_resolution(self):
"""
Return render resolution after rotation
Expand All @@ -165,7 +206,8 @@ def get_render_resolution(self):

def get_current_resolution(self):
w, h = self.display_info["width"], self.display_info["height"]
if self.display_info["orientation"] in [wda.LANDSCAPE, 'UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT']:
if self.display_info["orientation"] in [ROTATION_MODE.LANDSCAPE.name,
ROTATION_MODE.UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT.name]:
w, h = h, w
return w, h

Expand Down Expand Up @@ -216,20 +258,6 @@ def snapshot(self, filename=None, strType=False, quality=10, max_size=None):
traceback.print_exc()
return None

h, w = screen.shape[:2]

# save last res for portrait
if self.orientation in [wda.LANDSCAPE, 'UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT']:
self._size['height'] = w
self._size['width'] = h
else:
self._size['height'] = h
self._size['width'] = w

winw, winh = self.window_size()

self._touch_factor = float(winh) / float(h)

# save as file if needed
if filename:
aircv.imwrite(filename, screen, quality, max_size=max_size)
Expand Down Expand Up @@ -430,50 +458,29 @@ def _touch_point_by_orientation(self, tuple_xy):
"""
x, y = tuple_xy
try:
app_current_dict = self.app_current()
app_current_bundleId = app_current_dict.get('bundleId')
LOGGING.info("app_current_bundleId %s", app_current_bundleId)
except Exception as err:
LOGGING.error(err)
app_current_bundleId = 'example_bundleID'
if app_current_bundleId not in ['com.apple.springboard']:
return x, y

# use correct w and h due to now orientation
# _size 只对应竖直时候长宽
now_orientation = self.orientation

LOGGING.info("current orientation for %s", now_orientation)
if now_orientation in ['PORTRAIT', 'UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN']:
width, height = self._size['width'], self._size["height"]
else:
height, width = self._size['width'], self._size["height"]

LOGGING.info("current save window_size for (%s, %s)", self._size['width'], self._size["height"])
# check if not get screensize when touching
if not width or not height:
# use snapshot to get current resuluton
self.snapshot()
# use the new get screen size to reinitialize width and height
if now_orientation in ['PORTRAIT', 'UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN']:
width, height = self._size['width'], self._size["height"]
else:
height, width = self._size['width'], self._size["height"]

x, y = XYTransformer.up_2_ori(
(x, y),
(width, height),
now_orientation
)
# 部分设备如ipad,在横屏+桌面的情况下,点击坐标依然需要按照竖屏坐标额外做一次旋转处理
if self.is_pad and self.orientation in [ROTATION_MODE.LANDSCAPE.name, ROTATION_MODE.LANDSCAPE_RIGHT.name]:
app_current_bundleid = self.app_current()["bundleId"]
if app_current_bundleid not in ['com.apple.springboard']:
return x, y

if not (x < 1 and y < 1):
x, y = XYTransformer.up_2_ori(
(x, y),
(self.display_info['width'], self.display_info["height"]),
self.orientation
)
else:
x, y = y, x
return x, y

def _transform_xy(self, pos):
x, y = self._touch_point_by_orientation(pos)

# scale touch postion
if not (x < 1 and y < 1):
x, y = int(x * self._touch_factor), int(y * self._touch_factor)
x, y = int(x * self.touch_factor), int(y * self.touch_factor)

return x, y

Expand Down
19 changes: 16 additions & 3 deletions tests/test_ios.py
Expand Up @@ -7,7 +7,7 @@
from .testconf import try_remove

text_flag = True # 控制是否运行text接口用例
skip_alert_flag = True # 控制是否测试alert相关接口用例
skip_alert_flag = False # 控制是否测试alert相关接口用例
DEFAULT_ADDR = "http://localhost:8100/" # iOS设备连接参数
PKG_SAFARI = 'com.apple.mobilesafari'

Expand Down Expand Up @@ -87,7 +87,8 @@ def test_text(self):
def test_touch(self):
# 位置参数可为:相对于设备的百分比坐标或者实际的逻辑位置坐标
print("test_touch")
self.ios.touch((478, 360), duration=1)
self.ios.touch((480, 350), duration=0.1)
time.sleep(2)
self.ios.home()
time.sleep(2)
self.ios.touch((0.3, 0.3))
Expand Down Expand Up @@ -190,13 +191,25 @@ def test_alert_click(self):
print("test_get_alert_click")
self.ios.alert_click(['设置', '允许', '好'])

@unittest.skipIf(skip_alert_flag, "demonstrating skipping get_alert_click")
def test_alert_watch_and_click(self):
with self.ios.alert_watch_and_click(['Cancel']):
time.sleep(5)

# default watch buttons are
# ["使用App时允许", "好", "稍后", "稍后提醒", "确定", "允许", "以后"]
with self.ios.alert_watch_and_click(interval=2.0): # default check every 2.0s
time.sleep(5)

def test_device_info(self):
print("test_device_info")
print(self.ios.device_info())

def test_home_interface(self):
print("test_home_interface")
print(self.ios.home_interface())
self.ios.home()
time.sleep(2)
self.assertTrue(self.ios.home_interface())



Expand Down

0 comments on commit b377894

Please sign in to comment.