My application has a map-like canvas where the user can move by dragging the map around. What I'm trying to accomplish is move the map to the right of 100px and then to the left of 100px and check if the position in the center is the same.
The code is as follows:
device.drag((640, 360), (640 - 100, 360))
device.drag((640, 360), (640 + 100, 360))
# check
This doesn't reliably bring the map to the same place every time. Sometimes the device hangs or is slow and it moves few extra pixels; some other times in the last move step it goes faster, giving it momentum.
Is there any way to precisely drag the screen of a certain amount of pixels? If the device hangs or is slow it doesn't matter, as long as the movement in the end is correct.
I've tried to tweak the third (duration
) and fourth (steps
) argument to no avail.
I've also tried to implement my custom drag code with:
# Touch down screen
device.touch(100, 500, MonkeyDevice.DOWN)
# Move from 100, 500 to 200, 500
for i in range(1, 11):
device.touch(100 + 10 * i, 500, MonkeyDevice.MOVE)
time.sleep(0.1)
# Extra sleep to avoid momentum
time.sleep(0.2)
# Remove finger from screen
device.touch(200, 500, MonkeyDevice.UP)
and then to the other side:
# Touch down screen
device.touch(200, 500, MonkeyDevice.DOWN)
# Move from 200, 500 to 100, 500
for i in range(1, 11):
device.touch(200 - 10 * i, 500, MonkeyDevice.MOVE)
time.sleep(0.1)
# Extra sleep to avoid momentum
time.sleep(0.2)
# Remove finger from screen
device.touch(100, 500, MonkeyDevice.UP)
In a similar fashion I've also tried to test my game pad keys with:
for _ in range(0, 10):
device.press('KEYCODE_DPAD_RIGHT', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.1)
for _ in range(0, 10):
device.press('KEYCODE_DPAD_LEFT', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.1)
and even then sometimes monkeyrunner
will either skip events or not consider the up event and therefore causing a long press (which is equivalent to "keep moving on the map").
Very good question. After reading it I was also intrigued and I wonder if the problem affects AndroidViewClient/culebra too (which is more reliable).
However, as the folowing steps can tell it might be more related to the way Maps moves than the reliability of the different protocols sending envents. Also, a methond of automating the test is given, as you mentioned that you were doing a visual comparison of the results.
I think it would be of great help to share this and it may give you additional ideas to test your app.
Started by creating a test using culebra GUI.
Then I slightly edited the test to factor the points and add the opposite drag.
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2016 Diego Torres Milano
Created on 2017-03-04 by Culebra
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
try:
sys.path.insert(0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
import pkg_resources
pkg_resources.require('androidviewclient>=13.0.0')
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper, UiScrollable, UiObject, UiObject2
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'forceviewserveruse': False, 'useuiautomatorhelper': False, 'ignoreuiautomatorkilled': True, 'autodump': False, 'startviewserver': True, 'compresseddump': True}
cls.options = {'start-activity': None, 'concertina': False, 'device-art': None, 'use-jar': False, 'multi-device': False, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': False, 'dictionary-keys-from': 'id', 'scale': 1, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'log-actions': False, 'use-regexps': False, 'null-back-end': False, 'auto-regexps': None, 'do-not-verify-screen-dump': True, 'verbose-comments': False, 'gui': False, 'find-views-with-text': True, 'prepend-to-sys-path': False, 'install-apk': None, 'drop-shadow': False, 'output': None, 'unit-test-method': None, 'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
d = '/tmp/'
p = (377.14, 380.86)
q = (175.14, 380.86)
self.vc.writeImageToFile(d + 'map-start.png')
# Each step execution is throttled to 5ms per step
# So for a 400 steps, the swipe will take about 2 second to complete
steps = 400
duration = 2000
# Let's give some extra delay.
sleep = 3
for n in range(10):
print n
self.device.dragDip(p, q, duration, steps)
self.vc.sleep(sleep)
self.device.dragDip(q, p, duration, steps)
self.vc.sleep(sleep)
self.vc.writeImageToFile(d + 'map-finish.png')
self.device.compare(d + 'map-finish.png', d + 'map-start.png', d + 'map-compare.png')
if __name__ == '__main__':
CulebraTests.main()
Once run it, these are the results before and after the iterations
In this last image, you can see the visual comparison and it reveals there a slight movement. However, I think this might be just the way Maps do it.
I also used CulebraTester which uses a completely different backend based on UiAutomator and the same problem shows up. So I don't think is something related to drag
.