apkcrawler: Determine device dimensions.
Grab the device height, width, and calculate the height of the navbar
instead of hardcoding them.
Change-Id: Iafad6eccb6518b9bdb670f3f747709db237f96e7
diff --git a/apkcrawler/crawlui.py b/apkcrawler/crawlui.py
index f94769e..08dea1b 100644
--- a/apkcrawler/crawlui.py
+++ b/apkcrawler/crawlui.py
@@ -15,12 +15,9 @@
ADB_PATH = None
-# Nexus 6 dimensions.
-MAX_WIDTH = 1440
-# TODO(afergan): For layouts longer than the width of the screen, scroll down
-# and click on them. For now, we ignore them.
-MAX_HEIGHT = 2560
-NAVBAR_HEIGHT = 84
+MAX_HEIGHT = 0
+MAX_WIDTH = 0
+NAVBAR_HEIGHT = 0
# Visibility
VISIBLE = 0x0
@@ -32,18 +29,42 @@
EXITED_APP = 'exited app'
+def extract_between(text, sub1, sub2, nth=1):
+ """Extract a substring from text between two given substrings."""
+ # Credit to
+ # https://www.daniweb.com/programming/software-development/code/446964/extract-a-string-between-2-substrings-python-
+
+ # Prevent sub2 from being ignored if it's not there.
+ if sub2 not in text.split(sub1, nth)[-1]:
+ return None
+ return text.split(sub1, nth)[-1].split(sub2, nth)[0]
+
+
def set_adb_path():
"""Define the ADB path based on operating system."""
try:
global ADB_PATH
# For machines with multiple installations of adb, use the last listed
# version of adb. If this doesn't work for your setup, modify to taste.
- ADB_PATH = subprocess.check_output(['which -a adb'], shell=True).split(
- '\n')[-2]
+ ADB_PATH = (subprocess.check_output(['which -a adb'], shell=True)
+ .split('\n')[-2])
except subprocess.CalledProcessError:
print 'Could not find adb. Please check your PATH.'
+def set_device_dimens(vc):
+ """Sets global variables to the dimensions of the device."""
+ global MAX_HEIGHT, MAX_WIDTH, NAVBAR_HEIGHT
+ vc_dump = vc.dump(window='-1')
+ proc = subprocess.Popen([ADB_PATH, 'shell', 'wm size'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ size, _ = proc.communicate()
+ MAX_HEIGHT = extract_between(size, 'x', '\r')
+ MAX_WIDTH = extract_between(size, ': ', 'x')
+ NAVBAR_HEIGHT = (vc_dump[0].getY() - int(vc_dump[0]
+ ['layout:getLocationOnScreen_y()']))
+
+
def perform_press_back():
subprocess.call([ADB_PATH, 'shell', 'input', 'keyevent', '4'])
@@ -61,7 +82,7 @@
# If a popup menu has captured the focus, the focus will be in the format
# mCurrentFocus=Window{8f1328e u0 PopupWindow:53a5957}
if 'PopupWindow' in activity_str:
- popup_str = activity_str[activity_str.find('PopupWindow'):].split('}')[0]
+ popup_str = extract_between(activity_str, 'PopupWindow', '}')
return popup_str.replace(':', '')
# We are no longer in the app.
@@ -104,7 +125,7 @@
# mCurrentFocus=Window{35f66c3 u0 com.google.zagat/com.google.android.apps.
# zagat.activities.BrowseListsActivity}
# We want the text before the /
- pkg_name = activity_str.split('/')[0].split(' ')[-1]
+ pkg_name = extract_between(activity_str, ' ', '/', -1)
print 'Package name is ' + pkg_name
return pkg_name
@@ -174,7 +195,7 @@
if (component.isClickable() and component.getVisibility() == VISIBLE and
component.getX() >= 0 and component.getX() <= MAX_WIDTH and
int(component['layout:getWidth()']) > 0 and
- component.getY() >= (NAVBAR_HEIGHT) and
+ component.getY() >= NAVBAR_HEIGHT and
component.getY() <= MAX_HEIGHT and
int(component['layout:getHeight()']) > 0):
print component['class'] + '-- will be clicked'
@@ -186,6 +207,8 @@
def crawl_package(apk_dir, vc, device, debug, package_name=None):
"""Main crawler loop. Evaluate views, store new views, and click on items."""
set_adb_path()
+ set_device_dimens(vc)
+
view_root = []
view_array = []