From f7b30c3129aabb45384c30591ac66f6a1ddab15e Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Fri, 28 Jul 2017 15:13:45 +0200 Subject: [PATCH 01/15] fix python error when files already exist related to : ``` File "/usr/lib/python3.5/runpy.py", line 184, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.5/runpy.py", line 85, in _run_code exec(code, run_globals) File "/root/src/app.py", line 189, in run() File "/root/src/app.py", line 178, in run prepare_avd(device, avd_name) File "/root/src/app.py", line 74, in prepare_avd os.symlink(os.path.join(skin_rsc_path, s), os.path.join(skin_dst_path, s)) FileExistsError: [Errno 17] File exists: '/root/devices/skins/galaxy_nexus' -> '/root/platforms/android-25/skins/galaxy_nexus' Traceback (most recent call last): File "/usr/lib/python3.5/runpy.py", line 184, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.5/runpy.py", line 85, in _run_code exec(code, run_globals) File "/root/src/app.py", line 189, in run() File "/root/src/app.py", line 178, in run prepare_avd(device, avd_name) File "/root/src/app.py", line 74, in prepare_avd os.symlink(os.path.join(skin_rsc_path, s), os.path.join(skin_dst_path, s)) FileExistsError: [Errno 17] File exists: '/root/devices/skins/galaxy_nexus' -> '/root/platforms/android-25/skins/galaxy_nexus' ``` --- src/app.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app.py b/src/app.py index de493a2..13372f4 100644 --- a/src/app.py +++ b/src/app.py @@ -11,6 +11,15 @@ from src import log log.init() logger = logging.getLogger('app') +def symlink_force(target, link_name): + try: + os.symlink(target, link_name) + except OSError, e: + if e.errno == errno.EEXIST: + os.remove(link_name) + os.symlink(target, link_name) + else: + raise e def get_or_raise(env: str) -> str: """ @@ -71,7 +80,7 @@ def prepare_avd(device: str, avd_name: str): skin_dst_path = os.path.join(ANDROID_HOME, 'platforms', 'android-{api}'.format(api=API_LEVEL), 'skins') logger.info('Skin destination path: {dst}'.format(dst=skin_dst_path)) for s in os.listdir(skin_rsc_path): - os.symlink(os.path.join(skin_rsc_path, s), os.path.join(skin_dst_path, s)) + symlink_force(os.path.join(skin_rsc_path, s), os.path.join(skin_dst_path, s)) # Hardware and its skin device_name_bash = device.replace(' ', '\ ') @@ -85,7 +94,7 @@ def prepare_avd(device: str, avd_name: str): profile_src_path = os.path.join(ROOT, 'devices', 'profiles', '{profile}.xml'.format(profile=skin_name)) logger.info('Hardware profile resource path: {rsc}'.format(rsc=profile_src_path)) logger.info('Hardware profile destination path: {dst}'.format(dst=profile_dst_path)) - os.symlink(profile_src_path, profile_dst_path) + symlink_force(profile_src_path, profile_dst_path) # Append command cmd += ' -d {device} -s {skin}'.format(device=device_name_bash, skin=skin_name) From e56eb0e3ab7b0ade504a8cfe67ae96bd778bd01e Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Fri, 28 Jul 2017 22:45:34 +0200 Subject: [PATCH 02/15] fix : file already exist on start and stop container --- supervisord.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supervisord.conf b/supervisord.conf index a4b185b..340e443 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -4,7 +4,7 @@ logfile=%(ENV_LOG_PATH)s/supervisord.log childlogdir=%(ENV_LOG_PATH)s [program:xvfb] -command=/usr/bin/Xvfb %(ENV_DISPLAY)s -screen %(ENV_SCREEN)s %(ENV_SCREEN_WIDTH)sx%(ENV_SCREEN_HEIGHT)sx%(ENV_SCREEN_DEPTH)s +command=rm -r /tmp/ && /usr/bin/Xvfb %(ENV_DISPLAY)s -screen %(ENV_SCREEN)s %(ENV_SCREEN_WIDTH)sx%(ENV_SCREEN_HEIGHT)sx%(ENV_SCREEN_DEPTH)s stdout_logfile=%(ENV_LOG_PATH)s/xvfb.stdout.log stderr_logfile=%(ENV_LOG_PATH)s/xvfb.stderr.log From 486fb5825bc6e9296ac5a504fe951312da813d20 Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Sat, 29 Jul 2017 22:51:36 +0200 Subject: [PATCH 03/15] fix bad python impl --- src/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app.py b/src/app.py index 13372f4..3c7aaca 100644 --- a/src/app.py +++ b/src/app.py @@ -4,6 +4,7 @@ import json import logging import os import subprocess +import errno from src import CONFIG_FILE, ROOT, CHROME_DRIVER from src import log @@ -14,7 +15,7 @@ logger = logging.getLogger('app') def symlink_force(target, link_name): try: os.symlink(target, link_name) - except OSError, e: + except OSError as e: if e.errno == errno.EEXIST: os.remove(link_name) os.symlink(target, link_name) From e2ad6b75d2a7ff00b63a3b101f58b74957390a71 Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Mon, 31 Jul 2017 15:12:46 +0200 Subject: [PATCH 04/15] add unit test to symlink_force --- src/tests/unit/test_app.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/unit/test_app.py b/src/tests/unit/test_app.py index 93c555e..8acf3d5 100644 --- a/src/tests/unit/test_app.py +++ b/src/tests/unit/test_app.py @@ -9,6 +9,19 @@ from src import app class TestApp(TestCase): """Unit test class to test other methods in the app.""" + def test_symlink_correct(self): + os.mknod(os.path.join("./","testFile1.txt")) + app.symlink_force(os.path.join("./","testFile1.txt"),os.path.join("./","link_testFile1.txt")) + os.remove(os.path.join("./","testFile1.txt")) + os.remove(os.path.join("./","link_testFile1.txt")) + + """ link already exist""" + def test_symlink_already_exist(self): + os.mknod(os.path.join("./","testFile2.txt")) + os.mknod(os.path.join("./","link_testFile2.txt")) + app.symlink_force(os.path.join("./","testFile2.txt"),os.path.join("./","link_testFile2.txt")) + os.remove(os.path.join("./","testFile2.txt")) + os.remove(os.path.join("./","link_testFile2.txt")) def test_valid_env(self): key = 'ENV_1' From 9d3cb60f41e0f72e1ef2986f1f5bad9180593221 Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Mon, 31 Jul 2017 15:28:33 +0200 Subject: [PATCH 05/15] add unit test last case --- src/tests/unit/test_app.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tests/unit/test_app.py b/src/tests/unit/test_app.py index 8acf3d5..0b74431 100644 --- a/src/tests/unit/test_app.py +++ b/src/tests/unit/test_app.py @@ -9,6 +9,8 @@ from src import app class TestApp(TestCase): """Unit test class to test other methods in the app.""" + + """create symlink""" def test_symlink_correct(self): os.mknod(os.path.join("./","testFile1.txt")) app.symlink_force(os.path.join("./","testFile1.txt"),os.path.join("./","link_testFile1.txt")) @@ -22,6 +24,11 @@ class TestApp(TestCase): app.symlink_force(os.path.join("./","testFile2.txt"),os.path.join("./","link_testFile2.txt")) os.remove(os.path.join("./","testFile2.txt")) os.remove(os.path.join("./","link_testFile2.txt")) + + """test if other exception pop""" + def test_symlink_other_except(self): + with self.assertRaises(Exception): + app.symlink_force(os.path.join("./","testFile3.txt"),os.path.join("./","link_testFile3.txt")) def test_valid_env(self): key = 'ENV_1' From 648010d519dc3f2b064317fbdd982e486bb4ad2e Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Mon, 31 Jul 2017 15:56:50 +0200 Subject: [PATCH 06/15] delete useless code --- src/app.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app.py b/src/app.py index 3c7aaca..aeaad8a 100644 --- a/src/app.py +++ b/src/app.py @@ -19,8 +19,6 @@ def symlink_force(target, link_name): if e.errno == errno.EEXIST: os.remove(link_name) os.symlink(target, link_name) - else: - raise e def get_or_raise(env: str) -> str: """ From e1d6e3cdbe4446fc393c058549498eb4dd745ff1 Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Mon, 31 Jul 2017 15:58:38 +0200 Subject: [PATCH 07/15] delete useless code --- src/tests/unit/test_app.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tests/unit/test_app.py b/src/tests/unit/test_app.py index 0b74431..c94fb04 100644 --- a/src/tests/unit/test_app.py +++ b/src/tests/unit/test_app.py @@ -25,11 +25,6 @@ class TestApp(TestCase): os.remove(os.path.join("./","testFile2.txt")) os.remove(os.path.join("./","link_testFile2.txt")) - """test if other exception pop""" - def test_symlink_other_except(self): - with self.assertRaises(Exception): - app.symlink_force(os.path.join("./","testFile3.txt"),os.path.join("./","link_testFile3.txt")) - def test_valid_env(self): key = 'ENV_1' os.environ[key] = 'test' From 7c48af9b842256704246bbc0744d317b2f51335b Mon Sep 17 00:00:00 2001 From: thelittlefireman Date: Tue, 1 Aug 2017 10:30:04 +0200 Subject: [PATCH 08/15] fix codacy-bot warrning --- src/tests/unit/test_app.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tests/unit/test_app.py b/src/tests/unit/test_app.py index c94fb04..c31ac2d 100644 --- a/src/tests/unit/test_app.py +++ b/src/tests/unit/test_app.py @@ -10,21 +10,23 @@ from src import app class TestApp(TestCase): """Unit test class to test other methods in the app.""" - """create symlink""" + #create symlink + @classmethod def test_symlink_correct(self): os.mknod(os.path.join("./","testFile1.txt")) app.symlink_force(os.path.join("./","testFile1.txt"),os.path.join("./","link_testFile1.txt")) os.remove(os.path.join("./","testFile1.txt")) os.remove(os.path.join("./","link_testFile1.txt")) - """ link already exist""" + #link already exist + @classmethod def test_symlink_already_exist(self): os.mknod(os.path.join("./","testFile2.txt")) os.mknod(os.path.join("./","link_testFile2.txt")) app.symlink_force(os.path.join("./","testFile2.txt"),os.path.join("./","link_testFile2.txt")) os.remove(os.path.join("./","testFile2.txt")) os.remove(os.path.join("./","link_testFile2.txt")) - + def test_valid_env(self): key = 'ENV_1' os.environ[key] = 'test' From 5029d335289a4a4778d53688c10c55ca8d36a957 Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Fri, 27 Oct 2017 20:59:19 +0200 Subject: [PATCH 09/15] Fixed error --- supervisord.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supervisord.conf b/supervisord.conf index 8bd9f14..1e206a2 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -5,7 +5,7 @@ childlogdir=%(ENV_LOG_PATH)s priority=1 [program:xvfb] -command=rm -r /tmp/ && /usr/bin/Xvfb %(ENV_DISPLAY)s -screen %(ENV_SCREEN)s %(ENV_SCREEN_WIDTH)sx%(ENV_SCREEN_HEIGHT)sx%(ENV_SCREEN_DEPTH)s +command=/usr/bin/Xvfb %(ENV_DISPLAY)s -screen %(ENV_SCREEN)s %(ENV_SCREEN_WIDTH)sx%(ENV_SCREEN_HEIGHT)sx%(ENV_SCREEN_DEPTH)s stdout_logfile=%(ENV_LOG_PATH)s/xvfb.stdout.log stderr_logfile=%(ENV_LOG_PATH)s/xvfb.stderr.log priority=1 @@ -50,7 +50,7 @@ stderr_logfile=%(ENV_LOG_PATH)s/docker-android.stderr.log priority=4 [program:auto-recording] -command=./src/record.sh +command=./src/record.sh auto_record autorestart=false stdout_logfile=%(ENV_LOG_PATH)s/video-recording.stdout.log stderr_logfile=%(ENV_LOG_PATH)s/video-recording.stderr.log From 95adfd1fbd73338fb14cd8fd8d5e70513c94c1c4 Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Fri, 27 Oct 2017 21:00:10 +0200 Subject: [PATCH 10/15] Installed jq --- docker/Emulator_arm | 3 +++ docker/Emulator_x86 | 3 +++ docker/Real_device | 3 +++ 3 files changed, 9 insertions(+) diff --git a/docker/Emulator_arm b/docker/Emulator_arm index e3fcead..c81d668 100644 --- a/docker/Emulator_arm +++ b/docker/Emulator_arm @@ -34,6 +34,8 @@ WORKDIR /root #------------------ # ffmpeg # Video recorder +# jq +# Sed for JSON data #================== RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \ xterm \ @@ -45,6 +47,7 @@ RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \ python-numpy \ net-tools \ ffmpeg \ + jq \ && rm -rf /var/lib/apt/lists/* #======= diff --git a/docker/Emulator_x86 b/docker/Emulator_x86 index 2de1fee..69ed2d5 100644 --- a/docker/Emulator_x86 +++ b/docker/Emulator_x86 @@ -34,6 +34,8 @@ WORKDIR /root #------------------ # ffmpeg # Video recorder +# jq +# Sed for JSON data #------------------ # KVM Package # for emulator x86 @@ -54,6 +56,7 @@ RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \ python-numpy \ net-tools \ ffmpeg \ + jq \ qemu-kvm \ libvirt-bin \ ubuntu-vm-builder \ diff --git a/docker/Real_device b/docker/Real_device index f208f71..daac469 100644 --- a/docker/Real_device +++ b/docker/Real_device @@ -34,6 +34,8 @@ WORKDIR /root #------------------ # ffmpeg # Video recorder +# jq +# Sed for JSON data #================== RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \ xterm \ @@ -45,6 +47,7 @@ RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \ python-numpy \ net-tools \ ffmpeg \ + jq \ && rm -rf /var/lib/apt/lists/* #======= From fcffca21ff35d15bb7305ace6516c810c285788b Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Fri, 27 Oct 2017 21:02:00 +0200 Subject: [PATCH 11/15] Fixed error due to file name --- src/record.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/record.sh b/src/record.sh index dc1a614..4380738 100644 --- a/src/record.sh +++ b/src/record.sh @@ -2,20 +2,18 @@ function start() { mkdir -p $VIDEO_PATH - sw=$(($SCREEN_WIDTH - 1)) - sh=$(($SCREEN_HEIGHT - 1)) - name="$DEVICE-$BROWSER-$(date '+%d/%m/%Y-%H:%M:%S')" + name="$(date '+%d_%m_%Y_%H_%M_%S').mp4" echo "Start video recording" - ffmpeg -video_size $swx$sh -framerate 15 -f x11grab -i ${DISPLAY} $VIDEO_PATH/$name -y + ffmpeg -video_size 1599x899 -framerate 15 -f x11grab -i $DISPLAY $VIDEO_PATH/$name -y } function stop() { echo "Stop video recording" - kill $(ps -ef | grep ffmpeg) + kill $(ps -ef | grep ffmpeg | awk '{print $2}') } function auto_record() { - if [ ! -z $AUTO_RECORD ]; then + if [ $AUTO_RECORD ]; then if [ ${AUTO_RECORD,,} = true ]; then echo "Auto recording is enable. It will record the video automatically as soon as appium receive test scenario!" @@ -23,7 +21,7 @@ function auto_record() { no_test=true while $no_test; do task=$(curl -s localhost:4723/wd/hub/sessions | jq -r '.value') - if [ -n "$task" ]; then + if [ -n $task ]; then sleep .5 else no_test=false @@ -34,7 +32,7 @@ function auto_record() { # Check if test is finished while [ $no_test = false ]; do task=$(curl -s localhost:4723/wd/hub/sessions | jq -r '.value') - if [ -n "$task" ]; then + if [ -n $task ]; then stop else sleep .5 @@ -42,4 +40,6 @@ function auto_record() { done fi fi -} \ No newline at end of file +} + +$@ From 08ff64d950781b944853b6f3eab6e614e932da25 Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Mon, 30 Oct 2017 20:41:27 +0100 Subject: [PATCH 12/15] Fixed docker-compose volume --- docker-compose.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index edae1cb..3780c3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,14 +14,13 @@ services: nexus_7.1.1: image: butomo1989/docker-android-x86-7.1.1 privileged: true - # Change path of apk that you want to test. I use sample_apk that I provide in folder "example" - volumes: - - $PWD/example/sample_apk:/root/tmp # Increase scale number if needed scale: 1 ports: - 6080 + # Change path of apk that you want to test. I use sample_apk that I provide in folder "example" volumes: + - $PWD/example/sample_apk:/root/tmp - ./video-nexus_7.1.1:/tmp/video environment: - DEVICE=Nexus 5 From 0ea71ea6b8a84de89c1214d572fdd5a1ad45eb8f Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Mon, 30 Oct 2017 20:42:36 +0100 Subject: [PATCH 13/15] Refactored auto-recording function --- src/record.sh | 54 ++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/record.sh b/src/record.sh index 4380738..e4c39bb 100644 --- a/src/record.sh +++ b/src/record.sh @@ -9,37 +9,39 @@ function start() { function stop() { echo "Stop video recording" - kill $(ps -ef | grep ffmpeg | awk '{print $2}') + kill $(ps -ef | grep [f]fmpeg | awk '{print $2}') } function auto_record() { - if [ $AUTO_RECORD ]; then - if [ ${AUTO_RECORD,,} = true ]; then - echo "Auto recording is enable. It will record the video automatically as soon as appium receive test scenario!" + echo "Auto record: $AUTO_RECORD" + sleep 6 - # Check if there is test running - no_test=true - while $no_test; do - task=$(curl -s localhost:4723/wd/hub/sessions | jq -r '.value') - if [ -n $task ]; then - sleep .5 - else - no_test=false - start - fi - done + while [ $AUTO_RECORD == "True" ]; do + # Check if there is test running + no_test=true + while $no_test; do + task=$(curl -s localhost:4723/wd/hub/sessions | jq -r '.value') + if [ "$task" == "" ] || [ "$task" == "[]" ]; then + sleep .5 + else + start & + no_test=false + fi + done - # Check if test is finished - while [ $no_test = false ]; do - task=$(curl -s localhost:4723/wd/hub/sessions | jq -r '.value') - if [ -n $task ]; then - stop - else - sleep .5 - fi - done - fi - fi + # Check if test is finished + while [ $no_test == false ]; do + task=$(curl -s localhost:4723/wd/hub/sessions | jq -r '.value') + if [ "$task" == "" ] || [ "$task" == "[]" ]; then + stop + no_test=true + else + sleep .5 + fi + done + done + + echo "Auto recording is disabled!" } $@ From 0d6356ba470a08e5c159b3aece500f666d0ba624 Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Wed, 1 Nov 2017 15:53:25 +0100 Subject: [PATCH 14/15] Upgraded README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 2ab0cc9..c2a0a37 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ List of Docker images |OSX / Windows|6.0|23|butomo1989/docker-android-arm-6.0|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-arm-6.0.svg)](https://microbadger.com/images/butomo1989/docker-android-arm-6.0 "Get your own image badge on microbadger.com")| |OSX / Windows|7.0|24|butomo1989/docker-android-arm-7.0|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-arm-7.0.svg)](https://microbadger.com/images/butomo1989/docker-android-arm-7.0 "Get your own image badge on microbadger.com")| |OSX / Windows|7.1.1|25|butomo1989/docker-android-arm-7.1.1|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-arm-7.1.1.svg)](https://microbadger.com/images/butomo1989/docker-android-arm-7.1.1 "Get your own image badge on microbadger.com")| +|Real Device|-|-|butomo1989/docker-android-real-device|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-real-device.svg)](https://microbadger.com/images/butomo1989/docker-android-real-device "Get your own image badge on microbadger.com")| List of Devices --------------- @@ -127,6 +128,10 @@ If you want to use appium to test UI of your android application, you need to sh docker run --privileged -d -p 6080:6080 -p 4723:4723 -p 5554:5554 -p 5555:5555 -v $PWD/example/sample_apk:/root/tmp -e DEVICE="Nexus 5" -e APPIUM=True -e CONNECT_TO_GRID=True -e APPIUM_HOST="127.0.0.1" -e APPIUM_PORT=4723 -e SELENIUM_HOST="172.17.0.1" -e SELENIUM_PORT=4444 --name android-container butomo1989/docker-android-x86-7.1.1 ``` +### Share Volume + +You can deactivate auto_record by changing the value to "False" in docker-compose file. e.g. change value to "False" in this [line]. + ### Docker-Compose ![][compose] @@ -202,6 +207,7 @@ docker exec -it android-container tail -f /var/log/supervisor/docker-android.std [docker android nexus]: [compose]: [connected_devices]: +[line]: [example of compose file]: [docker-compose]: [1.13.0]: From 988397318f9f2401fca1a04b1e0d8ee7c4772927 Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Fri, 3 Nov 2017 11:12:15 +0100 Subject: [PATCH 15/15] Updated README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c2a0a37..cf55f58 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ Advantages compare with other docker-android projects 2. Emulator for different devices / skins, such as Samsung Galaxy S6, LG Nexus 4, HTC Nexus One and more. 3. Ability to connect to Selenium Grid 4. Ability to control emulator from outside container by using adb connect -5. Open source with more features coming (monkey test, support real devices with screen mirroring and video recording) +5. Support real devices with screen mirroring +6. Ability to record video during test execution for debugging +7. Open source with more features coming List of Docker images --------------------- @@ -45,7 +47,7 @@ List of Docker images |OSX / Windows|6.0|23|butomo1989/docker-android-arm-6.0|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-arm-6.0.svg)](https://microbadger.com/images/butomo1989/docker-android-arm-6.0 "Get your own image badge on microbadger.com")| |OSX / Windows|7.0|24|butomo1989/docker-android-arm-7.0|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-arm-7.0.svg)](https://microbadger.com/images/butomo1989/docker-android-arm-7.0 "Get your own image badge on microbadger.com")| |OSX / Windows|7.1.1|25|butomo1989/docker-android-arm-7.1.1|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-arm-7.1.1.svg)](https://microbadger.com/images/butomo1989/docker-android-arm-7.1.1 "Get your own image badge on microbadger.com")| -|Real Device|-|-|butomo1989/docker-android-real-device|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-real-device.svg)](https://microbadger.com/images/butomo1989/docker-android-real-device "Get your own image badge on microbadger.com")| +|All |-|-|butomo1989/docker-android-real-device|[![](https://images.microbadger.com/badges/image/butomo1989/docker-android-real-device.svg)](https://microbadger.com/images/butomo1989/docker-android-real-device "Get your own image badge on microbadger.com")| List of Devices ---------------