<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://dustingram.com/skins/common/feed.css?164"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://dustingram.com/index.php?title=Special:NewPages&amp;feed=atom</id>
		<title>Dustin Ingram - New pages [en]</title>
		<link rel="self" type="application/atom+xml" href="http://dustingram.com/index.php?title=Special:NewPages&amp;feed=atom"/>
		<link rel="alternate" type="text/html" href="http://dustingram.com/wiki/Special:NewPages"/>
		<updated>2010-09-06T00:52:37Z</updated>
		<subtitle>Dustin Ingram</subtitle>
		<generator>MediaWiki 1.13.4</generator>

	<entry>
		<id>http://dustingram.com/wiki/Automated_Control_of_an_Android_Device_with_Python</id>
		<title>Automated Control of an Android Device with Python</title>
		<link rel="alternate" type="text/html" href="http://dustingram.com/wiki/Automated_Control_of_an_Android_Device_with_Python"/>
				<updated>2010-06-17T20:30:59Z</updated>
		
		<summary type="html">&lt;p&gt;Dustingram: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Intro==&lt;br /&gt;
As mentioned in my previous article, [[Device Screenshots with the Android Debug Bridge]], I'm currently working on an application which required the ability to get a live screenshot of my physical Android device. The second component to that problem, however, involved processing that image, and then automating a UI/Application response exactly like an actual user is (read: automatically touch the screen).&lt;br /&gt;
&lt;br /&gt;
Again, like the ability to grab the device's current display, I figured this would be simple to do through the Android Debug Bridge. However, as it turned out, this was much simpler than I expected, and unlike the screenshot tool, I could avoid using Java for this.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
The first hint that I could send various UI events to the device came from the documentation for the [http://developer.android.com/guide/developing/tools/monkey.html Android UI/Application Exerciser Monkey], although being able to send completely random events proved pretty useless. However, it led me to the [http://android.git.kernel.org/?p=platform/development.git;a=tree;f=cmds/monkey Git Repository] for the tool, which in turn had a [http://android.git.kernel.org/?p=platform/development.git;a=blob;f=cmds/monkey/README.NETWORK.txt README file] which described the Simple Protocol for Automated Network Control.&lt;br /&gt;
&lt;br /&gt;
==Using the Network Control Protocol==&lt;br /&gt;
From the README:&lt;br /&gt;
 The Simple Protocol for Automated Network Control was designed to be a&lt;br /&gt;
 low-level way to programmability inject KeyEvents and MotionEvents&lt;br /&gt;
 into the input system.  The idea is that a process will run on a host&lt;br /&gt;
 computer that will support higher-level operations (like conditionals,&lt;br /&gt;
 etc.) and will talk (via TCP over ADB) to the device in Simple&lt;br /&gt;
 Protocol for Automated Network Control.  For security reasons, the&lt;br /&gt;
 Monkey only binds to localhost, so you will need to use adb to setup&lt;br /&gt;
 port forwarding to actually talk to the device.&lt;br /&gt;
&lt;br /&gt;
What this means, in a nutshell, is that a developer can use any language to command an ADB device (on loopback) using a simple TCP message.&lt;br /&gt;
&lt;br /&gt;
The first step is to make the ADB forward TCP traffic on the localhost to the device, in this case, port &amp;lt;tt&amp;gt;1080&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $ ./adb forward tcp:1080 tcp:1080&lt;br /&gt;
&lt;br /&gt;
Simple! At this point, the README attempts to discuss all the possible commands. I was purely interested in a &amp;lt;tt&amp;gt;touch&amp;lt;/tt&amp;gt; command (which is, in fact, two commands), so if you're looking for something else, look at the [http://android.git.kernel.org/?p=platform/development.git;a=blob;f=cmds/monkey/README.NETWORK.txt README file].&lt;br /&gt;
&lt;br /&gt;
If touch is what you want, though, here's what you need to know:&lt;br /&gt;
&lt;br /&gt;
 Note that sending a full button press requires sending both the down&lt;br /&gt;
 and the up event for that key&lt;br /&gt;
&lt;br /&gt;
This means we need a &amp;lt;tt&amp;gt;touch down&amp;lt;/tt&amp;gt; command followed by a &amp;lt;tt&amp;gt;touch up&amp;lt;/tt&amp;gt; command, separated by a newline, as follows (which touches point &amp;lt;tt&amp;gt;(x=30,y=60)&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;touch down 30 60\ntouch up 30 60&amp;quot;&lt;br /&gt;
&lt;br /&gt;
'''Important:''' In practice, though, this won't work every single time. It seems that the device may get confused by a series of strung-together commands in quick succession, especially a pair of &amp;lt;tt&amp;gt;touch&amp;lt;/tt&amp;gt; events. In most practical applications, it would make sense send commands individually, and sleep in between -- after all, real users don't move that fast!&lt;br /&gt;
&lt;br /&gt;
==A Sample Python Script==&lt;br /&gt;
Using our new knowledge of Android's Simple Protocol for Automated Network Control, here's a very simple Python script to send a single pair of &amp;lt;tt&amp;gt;touch&amp;lt;/tt&amp;gt; events, using the &amp;lt;tt&amp;gt;socket&amp;lt;/tt&amp;gt; module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
TCP_IP = '127.0.0.1'&lt;br /&gt;
TCP_PORT = 1080&lt;br /&gt;
BUFFER_SIZE = 1024&lt;br /&gt;
&lt;br /&gt;
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;
s.connect((TCP_IP, TCP_PORT))&lt;br /&gt;
s.send(&amp;quot;touch down 30 60\ntouch up 30 60&amp;quot;)&lt;br /&gt;
data = s.recv(BUFFER_SIZE)&lt;br /&gt;
s.close()&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;Received: &amp;quot;, data&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And that's it!&lt;br /&gt;
&lt;br /&gt;
[[Category:Code]]&lt;br /&gt;
[[summary::Using Android's Simple Protocol for Automated Network Control to send touch events to a physical device using Python and a TCP socket. | ]]&lt;br /&gt;
[[timestamp::{{BORNONDATE}}|]]&lt;/div&gt;</summary>
		<author><name>Dustingram</name></author>	</entry>

	<entry>
		<id>http://dustingram.com/wiki/Device_Screenshots_with_the_Android_Debug_Bridge</id>
		<title>Device Screenshots with the Android Debug Bridge</title>
		<link rel="alternate" type="text/html" href="http://dustingram.com/wiki/Device_Screenshots_with_the_Android_Debug_Bridge"/>
				<updated>2010-06-16T20:28:05Z</updated>
		
		<summary type="html">&lt;p&gt;Dustingram: /* Starting the ADB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Intro==&lt;br /&gt;
Certain recent endeavors have lead me to desire a way to automatically get pixel-perfect screenshots of my physical Android device (Motorola Droid). I knew it was possible to use the &amp;quot;adb&amp;quot;, or Android Debug Bridge tool; however, the actual tool has a number of features I didn't need, plus I wanted to automate the entire process.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
A number of mailing list posters and/or bloggers, some dating back a couple years, have attempted a solution, but almost every one either depended on an out-of-date library, or simply didn't work. The majority of my solution is taken from &lt;br /&gt;
Jon Larimer's code [http://blog.codetastrophe.com/2008/12/using-androiddebugbridge-api-to-get.html here], but I had to make a number of modifications to render the resulting image properly.&lt;br /&gt;
&lt;br /&gt;
==Starting the ADB==&lt;br /&gt;
I had a minor issue getting the ADB started. What happens is, if the ADB server isn't started with the proper permissions (root), there will be no device access. The tricky thing is, if you've got Eclipse running with the Android plugins, it'll have started up the ADB server already, with basic permissions. The following is an example of what you'll get from a running server without enough permissions:&lt;br /&gt;
&lt;br /&gt;
 $ ./adb devices&lt;br /&gt;
 List of devices attached &lt;br /&gt;
 ????????????	no permissions&lt;br /&gt;
&lt;br /&gt;
The solution is:&lt;br /&gt;
&lt;br /&gt;
 $ ./adb kill-server&lt;br /&gt;
 $ sudo ./adb start-server&lt;br /&gt;
 * daemon not running. starting it now *&lt;br /&gt;
 * daemon started successfully *&lt;br /&gt;
 $ ./adb devices&lt;br /&gt;
 List of devices attached &lt;br /&gt;
 04XXXXXXXXXXXX13	device&lt;br /&gt;
&lt;br /&gt;
==Connecting to the ADB==&lt;br /&gt;
Create the DebugBridge as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
AndroidDebugBridge.init(false);&lt;br /&gt;
AndroidDebugBridge adb = AndroidDebugBridge.createBridge();&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
We're going to add an instance of our class as a device change listener, so we'll know when changes occur, like the connection to a device. This also means the class will implement &amp;lt;tt&amp;gt;IDeviceChangeListener&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Screenshot ss = new Screenshot();&lt;br /&gt;
AndroidDebugBridge.addDeviceChangeListener(ss);&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
Use this to collect all attached devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
IDevice[] devices = adb.getDevices();&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Getting the Raw Screenshot==&lt;br /&gt;
Get the RawImage from the device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
RawImage raw = device.getScreenshot();&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
Set up the BufferedImage with the appropriate dimensions:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Boolean landscape = false; &lt;br /&gt;
BufferedImage image = null;        &lt;br /&gt;
Dimension size = new Dimension();&lt;br /&gt;
int width2 = landscape ? raw.height : raw.width;&lt;br /&gt;
int height2 = landscape ? raw.width : raw.height;&lt;br /&gt;
&lt;br /&gt;
if (image == null) {&lt;br /&gt;
	image = new BufferedImage(width2, height2, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;
	size.setSize(image.getWidth(), image.getHeight());&lt;br /&gt;
} else {&lt;br /&gt;
	if (image.getHeight() != height2 || image.getWidth() != width2) {&lt;br /&gt;
		image = new BufferedImage(width2, height2, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;
		size.setSize(image.getWidth(), image.getHeight());&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
Finally, make the appropriate adjustments to the RawImage's RGB values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntax lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int index = 0;&lt;br /&gt;
int indexInc = raw.bpp &amp;gt;&amp;gt; 3;&lt;br /&gt;
for (int y = 0; y &amp;lt; raw.height; y++) {&lt;br /&gt;
	for (int x = 0; x &amp;lt; raw.width; x++, index += indexInc) {&lt;br /&gt;
		int value = raw.getARGB(index);&lt;br /&gt;
		if (landscape)&lt;br /&gt;
			image.setRGB(y, raw.width - x - 1, value);&lt;br /&gt;
		else&lt;br /&gt;
			image.setRGB(x, y, value);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntax&amp;gt;&lt;br /&gt;
There are also a number of overrides for our class to fill the requirements of the implementation, for the various changes &lt;br /&gt;
&lt;br /&gt;
==All together==&lt;br /&gt;
You can download the entire working class [[Media:Screenshot.java|here]].&lt;br /&gt;
&lt;br /&gt;
[[Category:Code]]&lt;br /&gt;
[[summary::Getting a screen shot of a live or emulated Android Device automatically using the Android Debug Bridge. | ]]&lt;br /&gt;
[[timestamp::{{BORNONDATE}}|]]&lt;/div&gt;</summary>
		<author><name>Dustingram</name></author>	</entry>

	</feed>