<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jeffrey Sambells &#187; Mobile</title>
	<atom:link href="http://jeffreysambells.com/category/mobile/feed/" rel="self" type="application/rss+xml" />
	<link>http://jeffreysambells.com</link>
	<description>Geek out AFK</description>
	<lastBuildDate>Sun, 05 Feb 2012 17:00:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>&#9734; Every Day</title>
		<link>http://jeffreysambells.com/posts/2012/01/03/every-day/</link>
		<comments>http://jeffreysambells.com/posts/2012/01/03/every-day/#comments</comments>
		<pubDate>Tue, 03 Jan 2012 23:00:31 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Lifestyle]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Resolutions]]></category>
		<category><![CDATA[health]]></category>
		<category><![CDATA[journal]]></category>
		<category><![CDATA[lifestyle]]></category>
		<category><![CDATA[photos]]></category>
		<category><![CDATA[picture]]></category>
		<category><![CDATA[posts]]></category>
		<category><![CDATA[resolutions]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=1379</guid>
		<description><![CDATA[Resolutions are interesting. Every year I do the normal New Year&#8217;s thing and make some resolutions that usually don&#8217;t pan out after the fist few weeks&#8211;mostly because I don&#8217;t tell anyone about them. This year is going to be different because my resolutions involve daily changes and I have some tools to help. Last year [...]<p><a href="http://jeffreysambells.com/posts/2012/01/03/every-day/">&#9734; Permalink</a></p>]]></description>
			<content:encoded><![CDATA[<p>Resolutions are interesting. Every year I do the normal New Year&#8217;s thing and make some resolutions that usually don&#8217;t pan out after the fist few weeks&#8211;mostly because I don&#8217;t tell anyone about them. This year is going to be different because my resolutions involve daily changes and I have some tools to help.</p>

<p>Last year there was a big catalyst for change in my life. I decided it was time to move on from the the company <a href="http://wecreate.com">I helped start</a> and <a href="http://www.speakfeel.ca/news/jeffrey-sambells-senior-manager-mobile-development/">pursue a career in mobile technologies</a>. This has been a wonderful change and the new start I need to make more change. To help even further, I&#8217;m making my resolutions public so that failure is not an option.</p>

<p>So, here&#8217;s my resolutions and the tools I&#8217;m using to achieve them. For now I&#8217;ll just tell you what the tools are and I&#8217;ll post later about how they help and how they&#8217;re working out:</p>

<h2>1. Live a healthy lifestyle</h2>

<p>I purposely didn&#8217;t choose &#8220;lose weight&#8221; or &#8220;exercise&#8221; as my ultimate goal isn&#8217;t a specific measurement. I just want to have more energy, be healthier, live longer and have more fun. My kids are really active and I find I&#8217;m often out of breath just playing with them for a few minutes in the living room. It&#8217;s time to really do something about it with the help of a <a href="http://jawbone.com/up">Jawbone UP</a>, <a href="http://www.loseit.com/">Loseit</a> and <a href="http://itunes.apple.com/us/app/fleetly-fitness/id400220868?mt=8">Fleety</a>. I already know where I&#8217;ve been going wrong in the past but a weekly summary will be very helpful to keeping goals in check and make sure everything is going as planned.</p>

<h2>2. Keep a daily journal</h2>

<p>I&#8217;ve always wanted to keep a journal and I&#8217;ve tried. In the past my goals have always been to high. I felt the need to write something inspiring and important every day&#8211;which is not feasible&#8211;so I just ended up overwhelmed and abandoning the project. Instead, I&#8217;m starting out small by using <a href="http://dayoneapp.com/">Day One</a> to jot down a few interesting notes. I&#8217;ll just write <em>something</em> every day and see where it goes from there.</p>

<h2>3. Take a picture a day</h2>

<p>This one&#8217;s easy, I just have to remember to do it. The <a href="http://everyday-app.com">Everyday</a> app is going to do most of the work and if I achieve my first goal then this will be a great way to actually see the progress throughout the year.</p>

<h2>4. Fill my family photo stream</h2>

<p>I really want to spend more time documenting the lives of my kids. They&#8217;re great subjects but every Christmas my wife and I go to do a photo album for the Grandparents and realize we only have a handful of photos for the year. We miss dozens of great opportunities. At the same time I don&#8217;t want to live the year through a camera so my iPhone 4S is going to be my documentation device of choice. It&#8217;s always in my pocket so I don&#8217;t have an excuse not to snap a few shots.</p>

<p>To make it more fun I&#8217;m going to grab some <a href="http://www.wired.com/gadgetlab/2011/11/olloclip-an-affordable-there-way-iphone-lens-adapter/">Olloclip lenses</a> and I&#8217;ve loaded the iPhone up with some great apps like <a href="http://instagr.am">Instagram</a>, <a href="http://itunes.apple.com/ca/app/time-lapse-camera-hd/id402616263?mt=8">TimeLaps</a>, <a href="http://itunes.apple.com/ca/app/photosynth/id430065256?mt=8">Photosynth</a>, <a href="http://itunes.apple.com/ca/app/snapseed/id439438619?mt=8">Snapseed</a>, <a href="http://itunes.apple.com/ca/app/imovie/id377298193?mt=8">iMovie</a> and <a href="http://itunes.apple.com/ca/app/id329670577?mt=8">Camera+</a>. Along with a <a href="http://www.studioneat.com/products/glif-for-iphone-4">Glif</a>, a <a href="http://joby.com/gorillapod">Gorillapod</a> and my <a href="http://lifehacker.com/5863222/use-your-iphones-headset-to-take-pictures-from-afar">earphones</a> I should be set.</p>

<h2>5. Write one decent post every Monday</h2>

<p>One well written post every Monday, created on my iPad, with others as I find time. Something related to mobile/iOS/Android or something I think you&#8217;ll find interesting. This will require research and a lot of reading and writing so <a href="http://reederapp.com">Reeder</a>, <a href="http://itunes.apple.com/ca/app/penultimate/id354098826?mt=8">Penultimate</a>, <a href="http://itunes.apple.com/us/app/phraseology/id484666152?mt=8">Phraseology</a>, <a href="http://www.instapaper.com/iphone">Instapaper</a>, and <a href="http://ios.wordpress.org/">WordPress</a> and going to come in very handy.</p>

<h2>6. Relax and Have Fun</h2>

<p>The rest of the time I&#8217;m going to relax and have fun with the family. Without my phone.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2012/01/03/every-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9734; Understanding the demokit.pde Arduino Sketch</title>
		<link>http://jeffreysambells.com/posts/2011/05/17/understanding-the-demokit-pde-arduino-sketch/</link>
		<comments>http://jeffreysambells.com/posts/2011/05/17/understanding-the-demokit-pde-arduino-sketch/#comments</comments>
		<pubDate>Tue, 17 May 2011 15:31:23 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Snippet]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=1274</guid>
		<description><![CDATA[Examples are great ways to learn a new language or technology. To demonstrate the functionality of the Android Open Accessory ADK, the kit comes with a demo Arduino Sketch that demonstrates how the device communicates with the Arduino Base Board and Android Demo Shield. Unfortunately I have yet to find any good documentation on the [...]<p><a href="http://jeffreysambells.com/posts/2011/05/17/understanding-the-demokit-pde-arduino-sketch/">&#9734; Permalink</a></p>]]></description>
			<content:encoded><![CDATA[<p>Examples are great ways to learn a new language or technology. To demonstrate the functionality of the Android Open Accessory ADK, the kit comes with a demo Arduino Sketch that demonstrates how the device communicates with the Arduino Base Board and Android Demo Shield. Unfortunately I have yet to find any good documentation on the example and how it works so I thought I&#8217;d comment on the file for those that may not understand.</p>

<p>The post is in &#8220;blog&#8221; format with paragraphs shoved into the middle of code. For reference you can <a href="https://gist.github.com/975769">find the original <code>demokit.pde</code> file over in this Gist</a>.</p>

<h2>demokit.pde</h2>

<p>The Arduino language is based on C/C++ so the file starts off with the typical headers you&#8217;ll need for the various libraries used in the sketch (servos, LEDs, capacitive touch, USB, etc).</p>

<pre><code>#include &lt;Wire.h&gt;
#include &lt;Servo.h&gt;
#include &lt;Max3421e.h&gt;
#include &lt;Usb.h&gt;
</code></pre>

<p>These two are the ones you added to the Arduino application libraries <a href="http://a.arduino.com">when you set up your system for ADK development</a>.</p>

<pre><code>#include &lt;AndroidAccessory.h&gt;
#include &lt;CapSense.h&gt;
</code></pre>

<p>Next, you&#8217;ll  see several &#8216;#define&#8217; constants. These indicate which pins are attached to which features on the Android Demo Shield. If you look at the shield, you&#8217;ll notice each pin has a corresponding number. For example <code>#define LED3_RED 2</code> indicates that the third LED&#8217;s red component pin is using #2 on the shield.</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2011/05/LED3_RED.png" alt="LED3 Red pin location" title="LED3_RED" /></figure></p>

<p>Technically you don&#8217;t need to do this and you could just use <code>2</code> throughout your code but defining a constant makes it much easier to read and understand the code when you use <code>LED3_RED</code> instead of referring to the board to see what pin <code>2</code> is.</p>

<pre><code>#define  LED3_RED       2
#define  LED3_GREEN     4
#define  LED3_BLUE      3

#define  LED2_RED       5
#define  LED2_GREEN     7
#define  LED2_BLUE      6

#define  LED1_RED       8
#define  LED1_GREEN     10
#define  LED1_BLUE      9

#define  SERVO1         11
#define  SERVO2         12
#define  SERVO3         13

#define  TOUCH_RECV     14
#define  TOUCH_SEND     15

#define  RELAY1         A0
#define  RELAY2         A1

#define  LIGHT_SENSOR   A2
#define  TEMP_SENSOR    A3

#define  BUTTON1        A6
#define  BUTTON2        A7
#define  BUTTON3        A8

#define  JOY_SWITCH     A9      // pulls line down when pressed
#define  JOY_nINT       A10     // active low interrupt input
#define  JOY_nRESET     A11     // active low reset output
</code></pre>

<p>Now it&#8217;s time to identify the actual accessory. Read my previous post on <a href="http://jeffreysambells.com/posts/2011/05/15/identifying-your-android-usb-accessory/">&#8220;Identifying Your Android USB Accessory
&#8220;</a> for more information but you can see here that the <code>demokit.pde</code> file identifies itself as version 1.0 of the Google DemoKit accessory.</p>

<pre><code>AndroidAccessory acc("Google, Inc.",
             "DemoKit",
             "DemoKit Arduino Board",
             "1.0",
             "http://www.android.com",
             "0000000012345678");
</code></pre>

<p>Now, all that&#8217;s left to do is initialize a few variables, setup the environment and then start the loop that will continuously run to evaluate the IO for the Arduion board.</p>

<pre><code>// Define an array for the servos
Servo servos[3];

// Initiate the touch sensor
// 10M ohm resistor on demo shield
CapSense   touch_robot = CapSense(TOUCH_SEND, TOUCH_RECV);

// Run the initial setup on the board
void setup();

// Loop and check for IO 
void loop();
</code></pre>

<h3>Initialization</h3>

<p>The <code>pinMode()</code> method is used to initialize the input and output pins on the Android Demo Shield. It configures the specified pin to behave either as an <code>INPUT</code> or an <code>OUTPUT</code>. Arduino pins default to <code>INPUT</code> so the mode doesn&#8217;t need to be explicitly set but its usually a good idea to do it anyway so that your code is clear and understandable.</p>

<p>For example, the <code>init_buttons</code> function identifies the pins for <code>BUTTON1</code>, <code>BUTTON2</code>, <code>BUTTON3</code> and <code>JOY_SWITCH</code> as input connections.</p>

<pre><code>void init_buttons()
{

    pinMode(BUTTON1, INPUT);
    pinMode(BUTTON2, INPUT);
    pinMode(BUTTON3, INPUT);
    pinMode(JOY_SWITCH, INPUT);
</code></pre>

<p>To identify the state of the buttons, a pin configured as an INPUT can have a <code>HIGH</code> or <code>LOW</code> value. Writing a <code>HIGH</code> value with will enable an internal 20K pullup resistor. Writing LOW will disable the pullup. The pullup resistor acts as a known value when no other input is present (such as when pressing the button). Later you can use <code>digitalRead()</code> to check the value to determine if the button has been pressed or not.</p>

<pre><code>    digitalWrite(BUTTON1, HIGH);
    digitalWrite(BUTTON2, HIGH);
    digitalWrite(BUTTON3, HIGH);
    digitalWrite(JOY_SWITCH, HIGH);
}
</code></pre>

<p>Output pins, such as the relays in <code>init_relays()</code> are also configured using the <code>pinMode()</code> function however no default value needs to be written to the relays because it is always told to be either on or off.</p>

<pre><code>// Initializes the relays as outputs
void init_relays()
{
    pinMode(RELAY1, OUTPUT);
    pinMode(RELAY2, OUTPUT);
}
</code></pre>

<p>The <code>digitalWrite()</code> method can also take varying values as inputs. For example, you may want to write an integer between 1 and 255 to represent the brightness of an LED. The <code>init_leds()</code> function sets all the LED pins as outputs and presets their output value to 1 (or bright).</p>

<pre><code>// Initialize the LED outputs
void init_leds()
{

    digitalWrite(LED1_RED, 1);
    digitalWrite(LED1_GREEN, 1);
    digitalWrite(LED1_BLUE, 1);

    pinMode(LED1_RED, OUTPUT);
    pinMode(LED1_GREEN, OUTPUT);
    pinMode(LED1_BLUE, OUTPUT);

    digitalWrite(LED2_RED, 1);
    digitalWrite(LED2_GREEN, 1);
    digitalWrite(LED2_BLUE, 1);

    pinMode(LED2_RED, OUTPUT);
    pinMode(LED2_GREEN, OUTPUT);
    pinMode(LED2_BLUE, OUTPUT);

    digitalWrite(LED3_RED, 1);
    digitalWrite(LED3_GREEN, 1);
    digitalWrite(LED3_BLUE, 1);

    pinMode(LED3_RED, OUTPUT);
    pinMode(LED3_GREEN, OUTPUT);
    pinMode(LED3_BLUE, OUTPUT);
}
</code></pre>

<p>The joystick controls are little tricker so I&#8217;m not going to go into it in this post. If you&#8217;re interested see the <code>init_joystick()</code> and related functions at the bottom of the <a href="https://gist.github.com/975769"><code>demokit.pde</code> file that comes with the kit</a>.</p>

<pre><code>void init_joystick(int threshold);
</code></pre>

<h3>Setup</h3>

<p>Now that all the necessary helper functions are defined we can look at the setup function. The <code>setup()</code> function begins serial communications with the device and then calls all the initialization methods you saw earlier.</p>

<pre><code>// These are a few variables to hold the state of the buttons.
byte b1, b2, b3, b4, c;

// Setup the board
void setup()
{
    // Begin communications.
    Serial.begin(115200);
    Serial.print("\r\nStart");

    init_leds();
    init_relays();
    init_buttons();
    init_joystick( 5 );
</code></pre>

<p>Next, <code>setup()</code> calibrates the capacitive touch sensor and sets the servos to their initial positions of 90 degrees.</p>

<pre><code>    // autocalibrate OFF
    touch_robot.set_CS_AutocaL_Millis(0xFFFFFFFF);

    servos[0].attach(SERVO1);
    servos[0].write(90);
    servos[1].attach(SERVO2);
    servos[1].write(90);
    servos[2].attach(SERVO3);
    servos[2].write(90);
</code></pre>

<p>Lastly, <code>setup()</code> assigns the current <code>HIGH</code> or <code>LOW</code> value of the buttons to <code>b1</code>, <code>b2</code>, <code>b3</code> and  <code>b4</code>. During the <code>loop</code> execution, these values will be compared to the values in the loop and used to determine if the button&#8217;s state has changed since the last loop.</p>

<pre><code>    b1 = digitalRead(BUTTON1);
    b2 = digitalRead(BUTTON2);
    b3 = digitalRead(BUTTON3);
    b4 = digitalRead(JOY_SWITCH);
    c = 0;
</code></pre>

<p>Now the setup power&#8217;s on the accessory.</p>

<pre><code>    acc.powerOn();
}
</code></pre>

<h3>Loop</h3>

<p>The <code>loop()</code> function is the heart beat of the Arduino Base Board. After creating and executing the <code>setup()</code> function, which is responsible for initializing the initial values, the loop begins it&#8217;s magic and loops consecutively, allowing the sketch to analyze and respond accordingly.</p>

<p>The loop in <code>demokit.pde</code> has two main responsibilities. First, if the device is connected, it will read any input and write output to the device as necessary. Second, if no device is connected it will reset all the initial values to await a new device connection.</p>

<pre><code>void loop()
{
    byte err;
    byte idle;
    static byte count = 0;
    byte msg[3];
    long touchcount;
</code></pre>

<p>Here it looks for a connection.</p>

<pre><code>    if (acc.isConnected()) {

        int len = acc.read(msg, sizeof(msg), 1);
        int i;
        byte b;
        uint16_t val;
        int x, y;
        char c0;
</code></pre>

<p>If the length of the input buffer from the attached Android device is greater than zero, the loop process the input command to determine what it should do.</p>

<pre><code>        if (len &gt; 0) {
</code></pre>

<p>The message format can be seen in the DemoKit Android App that also comes with the kit. If you take a look at the <code>sendCommand()</code> method in the <code>com.google.android.DemoKit.DemoKitActivity</code> class.  You&#8217;ll see something like this:</p>

<pre><code>...
buffer[0] = command;
buffer[1] = target;
buffer[2] = (byte) value; 
...
</code></pre>

<p>In the case of a LED or Servo command, the <code>command</code>&#8216;s value is <code>2</code> (<code>DemoKitActivity.LED_SERVO_COMMAND</code>), followed by the <code>target</code> and the <code>value</code> to associate with the target.</p>

<p>For example, you can see in the following code that the red, green and blue pins for each LED are updated, but only when <code>msg[0]</code> is 2 (<code>0x2</code>). The LED pin to update is defined in <code>msg[1]</code> (<code>0x0</code> thru <code>0x8</code> respectively) and the value is set using <code>msg[2]</code> and <code>analogWrite()</code>.</p>

<p>In the case of the value for a LED, the lower the value the brighter the light (or the higher the value the more black and darker the light). The DemoKit app on the Android device sends 255 when it wants a full bright light so the value is subtracted from  255 to set the appropriate value for &#8220;bright&#8221;.</p>

<pre><code>            // Assumes only one command per packet.
            if (msg[0] == 0x2) {
                if (msg[1] == 0x0)
                    analogWrite(LED1_RED, 255 - msg[2]);
                else if (msg[1] == 0x1)
                    analogWrite(LED1_GREEN, 255 - msg[2]);
                else if (msg[1] == 0x2)
                    analogWrite(LED1_BLUE, 255 - msg[2]);
                else if (msg[1] == 0x3)
                    analogWrite(LED2_RED, 255 - msg[2]);
                else if (msg[1] == 0x4)
                    analogWrite(LED2_GREEN, 255 - msg[2]);
                else if (msg[1] == 0x5)
                    analogWrite(LED2_BLUE, 255 - msg[2]);
                else if (msg[1] == 0x6)
                    analogWrite(LED3_RED, 255 - msg[2]);
                else if (msg[1] == 0x7)
                    analogWrite(LED3_GREEN, 255 - msg[2]);
                else if (msg[1] == 0x8)
                    analogWrite(LED3_BLUE, 255 - msg[2]);
</code></pre>

<p>The servo output uses the same <code>command</code> and is processed in the same if condition however setting the servo position is a little different. You can read more in the <a href="http://www.arduino.cc/en/Reference/Servo">Servo library</a> but the basics here are that the servo&#8217;s <a href="http://arduino.cc/en/Reference/ServoWrite"><code>write()</code> method</a> takes an angle for the servo and the <a href="http://www.arduino.cc/en/Reference/Map"><code>map()</code> method</a> is used to re-map the input value from one range (0-255) to another (0-180).</p>

<pre><code>                else if (msg[1] == 0x10)
                    servos[0].write(map(msg[2], 0, 255, 0, 180));
                else if (msg[1] == 0x11)
                    servos[1].write(map(msg[2], 0, 255, 0, 180));
                else if (msg[1] == 0x12)
                    servos[2].write(map(msg[2], 0, 255, 0, 180));

            } else if (msg[0] == 0x3) {
</code></pre>

<p>For the two relays on the Android Demo Shield, <code>msg[2]</code> is simply compared for a <code>HIGH</code> or <code>LOW</code> value and the board is updated accordingly.</p>

<pre><code>                if (msg[1] == 0x0)
                    digitalWrite(RELAY1, msg[2] ? HIGH : LOW);
                else if (msg[1] == 0x1)
                    digitalWrite(RELAY2, msg[2] ? HIGH : LOW);

            }

        }
</code></pre>

<p>At this point in the loop, all the input messages have been processed so the loop switches to checking all the output pins and sending any necessary messages to the device.  The message type for output is set to 1 and each individual output is checked.</p>

<pre><code>        msg[0] = 0x1;
</code></pre>

<p>For example, in the following code the state of <code>BUTTON1</code> is read into <code>b</code> and compared to <code>b1</code>. Earlier you saw how the read value of the pin associated with <code>BUTTON1</code> could be either <code>HIGH</code> or <code>LOW</code>. If the value of <code>b</code> differs from the value of <code>b1</code> (defined in <code>setup()</code> or in the previous run of the loop) then the state of the button has changed and the appropriate message is sent back to the connected Android device. At the same time, <code>b</code> is assigned to <code>b1</code> to indicate the new state for the next loop.</p>

<pre><code>        b = digitalRead(BUTTON1);
        if (b != b1) {
            msg[1] = 0;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b1 = b;
        }

        // Check button 2
        b = digitalRead(BUTTON2);
        if (b != b2) {
            msg[1] = 1;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b2 = b;
        }

        // Check button 3
        b = digitalRead(BUTTON3);
        if (b != b3) {
            msg[1] = 2;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b3 = b;
        }

        // Check for a press on the joystick button.
        b = digitalRead(JOY_SWITCH);
        if (b != b4) {
            msg[1] = 4;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b4 = b;
        }
</code></pre>

<p>Once all the digital reads for the buttons have completed, the demokit uses an <code>analogRead()</code> to determine the current values of the temperature sensor, the light sensor, the joystick and the capacitive touch sensor. At first I was confused by the use of a switch statement here until I realized the expense of an analog read. It takes about 100 microseconds to read an analog input, so the maximum reading rate is 10,000 times a second. That&#8217;s pretty good but we don&#8217;t want to slow things down unnecessarily, especially when environmental variables such as temperature and ambient light are not changing dramatically at a rapid pace. The <code>switch</code> and <code>count++ % 0x10</code> condition allows the loop to reduce the frequency of analog reads and only sample one analog read per loop.</p>

<pre><code>        switch (count++ % 0x10) {
        case 0:
            val = analogRead(TEMP_SENSOR);
            msg[0] = 0x4;
            msg[1] = val &gt;&gt; 8;
            msg[2] = val &amp; 0xff;
            acc.write(msg, 3);
            break;

        case 0x4:
            val = analogRead(LIGHT_SENSOR);
            msg[0] = 0x5;
            msg[1] = val &gt;&gt; 8;
            msg[2] = val &amp; 0xff;
            acc.write(msg, 3);
            break;

        case 0x8:
            read_joystick(&amp;x, &amp;y);
            msg[0] = 0x6;
            msg[1] = constrain(x, -128, 127);
            msg[2] = constrain(y, -128, 127);
            acc.write(msg, 3);
            break;

        case 0xc:
            touchcount = touch_robot.capSense(5);

            c0 = touchcount &gt; 750;

            if (c0 != c) {
                msg[0] = 0x1;
                msg[1] = 3;
                msg[2] = c0;
                acc.write(msg, 3);
                c = c0;
            }

            break;
        }
    } else {
</code></pre>

<p>As mentioned earlier, when a device is not connected (or was disconnected) the loop resets the outputs to the default values.</p>

<pre><code>        analogWrite(LED1_RED, 255);
        analogWrite(LED1_GREEN, 255);
        analogWrite(LED1_BLUE, 255);
        analogWrite(LED2_RED, 255);
        analogWrite(LED2_GREEN, 255);
        analogWrite(LED2_BLUE, 255);
        analogWrite(LED3_RED, 255);
        analogWrite(LED3_GREEN, 255);
        analogWrite(LED3_BLUE, 255);
        servos[0].write(90);
        servos[0].write(90);
        servos[0].write(90);
        digitalWrite(RELAY1, LOW);
        digitalWrite(RELAY2, LOW);
    }
</code></pre>

<p>Then the loop ends by delaying for a few milliseconds.</p>

<pre><code>    delay(10);
}
</code></pre>

<p>The <a href="https://gist.github.com/975769">remainder of the file</a> deals with the IO of the joystick. You can just take it as is and I&#8217;ll leave it until another post.</p>

<p>Hopefully this was a little helpful getting you started with the ADK and the demokit example.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2011/05/17/understanding-the-demokit-pde-arduino-sketch/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#9734; Debugging and sniffing mobile device traffic</title>
		<link>http://jeffreysambells.com/posts/2011/03/15/debugging-and-sniffing-mobile-device-traffic/</link>
		<comments>http://jeffreysambells.com/posts/2011/03/15/debugging-and-sniffing-mobile-device-traffic/#comments</comments>
		<pubDate>Tue, 15 Mar 2011 18:31:12 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[BlackBerry]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Snippet]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=1199</guid>
		<description><![CDATA[So, you&#8217;re developing you&#8217;re mobile web app when suddenly things start to go awry on the device. Request don&#8217;t seem to be sending out properly and your responses just don&#8217;t seem to be right. In a desktop environment you could easily pop open your web inspector to see what&#8217;s going on as network requests are [...]<p><a href="http://jeffreysambells.com/posts/2011/03/15/debugging-and-sniffing-mobile-device-traffic/">&#9734; Permalink</a></p>]]></description>
			<content:encoded><![CDATA[<p>So, you&#8217;re developing you&#8217;re mobile web app when suddenly things start to go awry on the device. Request don&#8217;t seem to be sending out properly and your responses just don&#8217;t seem to be right. In a desktop environment you could easily pop open your web inspector to see what&#8217;s going on as network requests are sent and received but in a mobile environment what are you to do? Well don&#8217;t fret, if you&#8217;ve got a Mac (or a PC with similar functionality) sniffing out device traffic is as easy as a few clicks.</p>

<p>The basic idea is that you&#8217;ll share your desktop&#8217;s internet connection with your mobile device and then watch any traffic you want from your desktop. This involves a few simple steps:</p>

<ol>
<li>Share your desktop&#8217;s internet connection.</li>
<li>Use the shared connection from your mobile device.</li>
<li>Sniff your traffic.</li>
</ol>

<h2>Sharing your desktop internet connection with your mobile device</h2>

<p>In a Mac environment this is easy (and you should be able to <a href="http://support.microsoft.com/kb/306126">do something similar in Windows</a>). The only requirement is that you&#8217;ll need a wireless card (comes built-in to all modern Macs) and you&#8217;ll need a second internet connection such as the ethernet port (since your wireless card will be occupied sharing your connection). Once you have these, simply go to:</p>

<p>Apple Menu > System Preferences&#8230; > Sharing (under Internet &amp; Wireless)</p>

<p>In this pane, click on the <strong>&#8220;Internet Sharing&#8221;</strong> text but don&#8217;t check the box yet. Select <strong>Ethernet</strong> from <strong>&#8220;Share your connection from&#8221;</strong> and then check the box next to <strong>AirPort</strong> in <strong>&#8220;To computers using&#8221;</strong>. Now check the box next to &#8220;Internet Sharing&#8221; on the left. It should look something like this:</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2011/03/Screen-shot-2011-03-15-at-1.36.32-PM-600x491.png" alt="" title="Apple's Internet Sharing Settings" class="wp-image-1202" /></figure></p>

<p>This tells your mac to take the incoming Internet connection on your Ethernet port and send it out to other connected devices on your wireless AirPort port. If everything went well you&#8217;ll also notice the icon for your AirPort connection looks like a little arrow pointing up:</p>

<p><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2011/03/Screen-shot-2011-03-15-at-1.37.20-PM.png" alt="" title="Screen shot 2011-03-15 at 1.37.20 PM" class="wp-image-1203"/>.</p>

<p><strong>NOTE: This creates an OPEN network without a password that anyone can connect to. If you&#8217;re in an area where you would rather have a private network, select the &#8220;AirPort Options&#8230;&#8221; button in the sharing pane and adjust settings as necessary before you start up your shared connection.</strong></p>

<h2>Connecting to the your shared connection from your mobile device.</h2>

<p>Now you can connect any Wi-Fi device to your shared network including other computers, iPhones, iPads, Android phones, whatever.</p>

<p>For an iOS device, simple go to:</p>

<p>Settings.app > Wi-Fi</p>

<p>and select your shared network (in my case &#8220;Jeffrey Sambellsâ€™s MacBook Pro&#8221;).</p>

<p>For Android you can find similar settings in Settings > Wireless &amp; Networks > Wi-Fi Settings.</p>

<p>Once you&#8217;re connected to your shared Wi-Fi your mobile device will act as usual but all it&#8217;s traffic will be routing through your desktop computer&#8211;perfect for sniffing.</p>

<p><em>TIP: I find it&#8217;s often a good idea to enable Airplane mode on your mobile device so that you can be sure the requests will go over Wi-Fi instead of the cell network. To do this, just turn on Airplane mode in settings and then enable just Wi-Fi to connect to your shared connection.</em></p>

<h2>Sniffing your mobile traffic.</h2>

<p>Now comes the fun part. Since all the traffic from your device is now routing through your shared network, you can watch that network and see what&#8217;s going on.</p>

<p>I&#8217;ve found the easiest way to do this is using an app like <a href="http://www.tuffcode.com/index.html">HTTPScoop</a>. If you set HTTPScoop watch your AirPort interface and then hit Scoop you&#8217;ll get a list of all the HTTP connections that occur to and from the mobile device:</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2011/03/Screen-shot-2011-03-15-at-2.07.29-PM-600x240.png" alt="" title="HTTPScoop List" class="wp-image-1204" /></figure></p>

<p>and you can inspect each request for headers, raw data and the content of the request:</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2011/03/Screen-shot-2011-03-15-at-2.07.55-PM-600x276.png" alt="" title="HTTP Inspection" class="wp-image-1205" /></figure></p>

<p>This is <strong>very</strong> useful for debugging you app&#8217;s requests and response as well as poking to see how other apps (including Apple&#8217;s built in apps) communicate with the network. Every wonder how map tiles load into the Maps.app? Or maybe you&#8217;re curious what info all your installed apps are sending out about you. Know you can find out.</p>

<p>If you need deeper details about the network traffic, there&#8217;s <a href="http://www.google.com/search?ie=UTF-8&amp;q=mac+os+x+packet+sniffing">a number of other apps you can use</a> that provide more details packet analysis.</p>

<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2011/03/15/debugging-and-sniffing-mobile-device-traffic/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#9734; Breaking through the firewall with SSH</title>
		<link>http://jeffreysambells.com/posts/2010/09/17/breaking-through-the-firewall-with-ssh/</link>
		<comments>http://jeffreysambells.com/posts/2010/09/17/breaking-through-the-firewall-with-ssh/#comments</comments>
		<pubDate>Fri, 17 Sep 2010 14:04:02 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Snippet]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=820</guid>
		<description><![CDATA[With mobile development I often find myself out-of-the-office away from the development resources I need on a daily basis. I was recently out-of-the-office (OK, I was at home sitting on my couch but close enough) and I needed to access a Windows machine at the office via Remote Desktop. The only problem was it was [...]]]></description>
			<content:encoded><![CDATA[<p>With mobile development I often find myself out-of-the-office away from the development resources I need on a daily basis. I was recently out-of-the-office (OK, I was at home sitting on my couch but close enough) and I needed to access a Windows machine at the office via Remote Desktop.  The only problem was it was behind a firewall in our companies internal 192.x.x.x network. Surprisingly, accessing it from home was quite simple.</p>

<p>I have a MacBook so I opened up the Terminal app and entered this:</p>

<pre><code>ssh -l jsambells -L 3390:192.168.1.100:3389 example.dev.box cat -
</code></pre>

<p>Then all I had to do on my MacBook was enter <code>localhost:3390</code> into Microsoft&#8217;s Remote Desktop Connection app and login to the Remote Desktop.</p>

<p>Huh?</p>

<p>This is what&#8217;s know as an <a href="http://en.wikipedia.org/wiki/Tunneling_protocol">SSH tunnel</a>. Basically it creates a secure connection that forwards a port on one machine to another. My above command contains several components:</p>

<ul>
<li><code>3390</code> is the local port on my MacBook that I&#8217;ll be using to connect to the Remote Desktop in the office. This could be any port above 1024 and below 32768. Doesn&#8217;t matter.</li>
<li><code>192.168.1.100</code> is the example IP address of the machine I want to access on the internal network. This IP must be accessible by the machine at <code>example.dev.box</code>.</li>
<li><code>3389</code> is the standard port number for Remote Desktop connections. </li>
<li><code>example.dev.box</code> is a publicly accessible machine that can also connect to the internal machine. </li>
<li><code>cat -</code> is a command that won&#8217;t finish so the connection stays alive.</li>
</ul>

<p>The trick here is that I needed a machine that could connect both the the internet at large and to the internal company network (which I happen to have at example.dev.box). The command uses an SSH tunnel to forward the traffic between <code>localhost:3390</code> and any connections to <code>192.168.1.100</code> on port <code>3389</code> of <code>example.dev.box</code>. Connecting locally at home to <code>localhost:3390</code> is the same as connecting to <code>192.168.1.100:3389</code> from <code>example.dev.box</code>.</p>

<p>You can use similar techniques to secure any traffic, such as your <a href="http://stopdesign.com/archive/2005/02/07/secure-email.html">email</a> or bypass firewall restrictions.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/09/17/breaking-through-the-firewall-with-ssh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9734; iOS Wireless App Distribution [Updated]</title>
		<link>http://jeffreysambells.com/posts/2010/06/22/ios-wireless-app-distribution/</link>
		<comments>http://jeffreysambells.com/posts/2010/06/22/ios-wireless-app-distribution/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 02:11:05 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Snippet]]></category>
		<category><![CDATA[XCode]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=677</guid>
		<description><![CDATA[UPDATE: There&#8217;s been a lot of interest in this post and Ad Hoc distribution methods. This is a very simple example so if you&#8217;re looking for an off-the-shelf solution, I suggest you check out testflightapp.com or Hockey which provide more robust features. With the new iPhone iOS 4, you can distribute apps wirelessly without iTunes [...]<p><a href="http://jeffreysambells.com/posts/2010/06/22/ios-wireless-app-distribution/">&#9734; Permalink</a></p>]]></description>
			<content:encoded><![CDATA[<p><em>UPDATE: There&#8217;s been a lot of interest in this post and Ad Hoc distribution methods. This is a very simple example so if you&#8217;re looking for an off-the-shelf solution, I suggest you check out <a href="http://testflightapp.com">testflightapp.com</a> or <a href="https://github.com/TheRealKerni/Hockey">Hockey</a> which provide more robust features.</em></p>

<p>With the new iPhone iOS 4, you can distribute apps wirelessly <em>without</em> iTunes intervention. You still need to collect the appropriate devices id&#8217;s and create the appropriate provisioning profiles but if you already have those sending out files is easy.</p>

<p>First, select &#8220;Build and Archive&#8221; from your XCode build menu. Your archived project will be stored in the &#8220;Archived Applications&#8221; section of the the XCode organizer (Window > Organizer).</p>

<p>Next, select the archive you want to distribute in the XCode organizer and select &#8220;Share Application&#8230;&#8221; at the bottom of the window. Pick the appropriate provisioning profile and then &#8220;Distribute for Enterprise&#8221;.</p>

<p>In the distribution window, enter the title and the full url to the <code>ipa</code> file (where you plan to host your app) for example, http://jeffreysambells.com/example.ipa.</p>

<p>Along with the generated .plist and the .ipa files, you&#8217;ll need the provisioning profile and a simple index file, for example:</p>

<pre><code>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;My Cool app&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://jeffreysambells.com/example.mobileprovision"&gt;
                Install Example Provisioning File&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="itms-services://?action=download-manifest&amp;url=http://jeffreysambells.com/example.plist"&gt;
                Install Example Application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>With these all uploaded to your server all you need to do is point people at the index file and they can select the links to install the provisioning profile and app directly from mobile safari on their iOS devices. A much nicer experience compared to installing through the iTunes sync process.</p>

<p><strong>UPDATE</strong></p>

<p>After re-publishing updates to my apps several times, I was finding it a little tedious to re-type the full url into the XCode tool&#8212;plus I could never remember what I named the damn files&#8212;so I came up with this quick and dirty <code>index.php</code> script to do the grunt work for me:</p>

<pre><code>&lt;?php

$ipas = glob('*.ipa');
$provisioningProfiles = glob('*.mobileprovision');
$plists = glob('*.plist');

$sr = stristr( $_SERVER['SCRIPT_URI'], '.php' ) === false ? 
    $_SERVER['SCRIPT_URI'] : dirname($_SERVER['SCRIPT_URI']) . '/';
$provisioningProfile = $sr . $provisioningProfiles[0];
$ipa = $sr . $ipas[0];
$itmsUrl = urlencode( $sr . 'index.php?plist=' . str_replace( '.plist', '', $plists[0] ) );


if ($_GET['plist']) {
    $plist = file_get_contents( dirname(__FILE__) 
        . DIRECTORY_SEPARATOR 
        . preg_replace( '/![A-Za-z0-9-_]/i', '', $_GET['plist']) . '.plist' );
    $plist = str_replace('_URL_', $ipa, $plist);
    header('content-type: application/xml');
    echo $plist;
    die();
}


?&gt;&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Install iOS App&lt;/title&gt;
&lt;style type="text/css"&gt;

li {
    padding: 1em;
}

&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="&lt;? echo $provisioningProfile; ?&gt;"&gt;Install Team Provisioning File&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="itms-services://?action=download-manifest&amp;url=&lt;? echo $itmsUrl; ?&gt;"&gt;
         Install Application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>It&#8217;s nothing fancy so you&#8217;ll probably want to spiff it up but to use it (you&#8217;ll need PHP), just create a folder and drop in the <code>index.php</code> along with the <code>.mobileprovision</code> file, the exported <code>.ipa</code> and the exported <code>.plist</code>. To make things easy just enter <code>_URL_</code> (uppercase url with underscores) as the &#8220;url&#8221; in XCode and the script will automatically fill in the proper URL as necessary. It doesn&#8217;t matter what the file names are as long as there is only one <code>.moblieprovision</code>, <code>.ipa</code> and <code>.plist</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/06/22/ios-wireless-app-distribution/feed/</wfw:commentRss>
		<slash:comments>79</slash:comments>
		</item>
		<item>
		<title>&#9734; Decoding Polylines from Google Maps Direction API with Java</title>
		<link>http://jeffreysambells.com/posts/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java/</link>
		<comments>http://jeffreysambells.com/posts/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java/#comments</comments>
		<pubDate>Thu, 27 May 2010 16:44:20 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Maps]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Directions]]></category>
		<category><![CDATA[GeoPoint]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Polyline]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=661</guid>
		<description><![CDATA[I&#8217;ve been integrating the new Google Maps Directions api into an Android app and couldn&#8217;t find a Java decoder for the Encoded Polyline Algorithm Format. After a little bit of grunt work here&#8217;s a working method that will convert an encoded result such as this: }wjiGtdpcNrAlBJZ into a nice GeoPoint array list: private List&#60;GeoPoint&#62; decodePoly(String [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been integrating the new <a href="http://code.google.com/apis/maps/documentation/directions/">Google Maps Directions api</a> into an Android app and couldn&#8217;t find a Java <em>decoder</em> for the <a href="http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html">Encoded Polyline Algorithm Format</a>. After a little bit of grunt work here&#8217;s a working method that will convert an encoded result such as this:</p>

<pre><code> }wjiGtdpcNrAlBJZ
</code></pre>

<p>into a nice GeoPoint array list:</p>

<pre><code>private List&lt;GeoPoint&gt; decodePoly(String encoded) {

    List&lt;GeoPoint&gt; poly = new ArrayList&lt;GeoPoint&gt;();
    int index = 0, len = encoded.length();
    int lat = 0, lng = 0;

    while (index &lt; len) {
        int b, shift = 0, result = 0;
        do {
            b = encoded.charAt(index++) - 63;
            result |= (b &amp; 0x1f) &lt;&lt; shift;
            shift += 5;
        } while (b &gt;= 0x20);
        int dlat = ((result &amp; 1) != 0 ? ~(result &gt;&gt; 1) : (result &gt;&gt; 1));
        lat += dlat;

        shift = 0;
        result = 0;
        do {
            b = encoded.charAt(index++) - 63;
            result |= (b &amp; 0x1f) &lt;&lt; shift;
            shift += 5;
        } while (b &gt;= 0x20);
        int dlng = ((result &amp; 1) != 0 ? ~(result &gt;&gt; 1) : (result &gt;&gt; 1));
        lng += dlng;

        GeoPoint p = new GeoPoint((int) (((double) lat / 1E5) * 1E6),
             (int) (((double) lng / 1E5) * 1E6));
        poly.add(p);
    }

    return poly;
}
</code></pre>

<p>If you need an encoder (or other decoders) check out Mark McClure&#8217;s page <a href="http://facstaff.unca.edu/mcmcclur/googlemaps/encodepolyline/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>&#9734; Android vs iPhone development decisions</title>
		<link>http://jeffreysambells.com/posts/2010/05/20/android-vs-iphone-development-decisions/</link>
		<comments>http://jeffreysambells.com/posts/2010/05/20/android-vs-iphone-development-decisions/#comments</comments>
		<pubDate>Fri, 21 May 2010 04:34:15 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=646</guid>
		<description><![CDATA[Release early, release often (sometimes abbreviated RERO) is a software development philosophy that emphasizes the importance of early and frequent releases in creating a tight feedback loop between developers and users. &#8212; Wikipedia To begin let me say that I&#8217;m both a web developer and a mobile application developer and I LOVE the &#8220;release early, [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>Release early, release often (sometimes abbreviated RERO) is a software development philosophy that emphasizes the importance of early and frequent releases in creating a tight feedback loop between developers and users.</p>
</blockquote>

<p>&#8212; Wikipedia</p>

<p>To begin let me say that I&#8217;m both a web developer and a mobile application developer and I LOVE the &#8220;release early, release often&#8221; philosophy for web development. RERO allows me to make quick updates and improvements and add great new features for all my users. RERO is great. It&#8217;s awesome. It works and all the developers and users using the application are happy.</p>

<p>On the other hand, I loath RERO when it comes to SDK&#8217;s. It&#8217;s just a flawed and utterly terrible idea when there&#8217;s no clear and very accessible upgrade path for end users. As a web developer, I would not be happy if Microsoft decided to release IE9, IE10 and IE11 in the span of a year. My workload would more than triple, my user base would fragment and I&#8217;d be endlessly adding kludges for each new version. Unfortunately this is what&#8217;s starting to happen with the Android SDK and, as a mobile developer, I&#8217;m starting to get worried.</p>

<h2>Android OS</h2>

<p>To understand how RERO can harm adoption let&#8217;s take a look at the <em>public</em> Android SDK release schedule:</p>

<ul>
<li>API Level 2, Android 1.1 &#8212; February 2009</li>
<li>API Level 3, Android 1.5 &#8212; April 2009</li>
<li>API Level 4, Android 1.6 &#8212; September 2009</li>
<li>API Level 5, Android 2.0 &#8212; October 2009</li>
<li>
<ul>
<li>API Level 6, Android 2.01 &#8212; December 2009</li>
</ul></li>
<li>API Level 7, Android 2.1 &#8212; January 2009</li>
<li>API Level 8, Android 2.2 &#8212; May 2009</li>
</ul>

<p>Wow. In the past fifteen months (a little over a year) there have been seven public releases of different versions of the Android SDK. That doesn&#8217;t include carrier or manufacturer revisions with different user interfaces. It&#8217;s not that I&#8217;m not happy with the advancements of the SDK. They&#8217;re all wonderful and obviously the Android team is working really hard but there&#8217;s a problem. If we take a look at Google&#8217;s published Platform Versions stats and we can see where developers have a tough decision:</p>

<p><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2010/05/chart.png" alt="" title="Android Platform Chart" width="460" height="250" class="aligncenter size-full wp-image-648" />
&#8212; <a href="http://developer.android.com/resources/dashboard/platform-versions.html">Source</a></p>

<p>More than 50% of the Android install base is still using version 1.6 or less. As a developer what should I do? If I choose to take advantage of the latest and greatest SDK I get less than half of the devices! But still, the bigger problem is there is no clear and easy upgrade path for those bottom 50% to get the newer OS version. Neither of my Google supplied development phones (which are only a year old) can be upgraded without a lot of illicit hacking and deep developer knowledge.</p>

<p>The Android OS is in deep trouble until there&#8217;s an easy way to upgrade the OS on every device that runs it.</p>

<h2>iPhone OS</h2>

<p>Now contrast this situation with iPhone OS. Apple has been lambasted by developers for their tight control and strict NDA rules regarding beta releases but in comparison to the situation with Android isn&#8217;t it better? The NDA period allows the SDK to be flushed out, before it is &#8220;publicly&#8221; available so that there is one complete well oiled version that all developers can target across a large set of devices.</p>

<p>The <em>public</em> iPhone SDK release timeline is also much longer:</p>

<ul>
<li>SDK 1.0 &#8211; June 2007 (not public)</li>
<li>SDK 2.0 &#8211; July 2008</li>
<li>SDK 3.0 &#8211; June 2009</li>
<li>
<ul>
<li>SDK 3.1 &#8211; September 2009</li>
</ul></li>
<li>
<ul>
<li>
<ul>
<li>SDK 3.1.2 &#8211; October 2009</li>
</ul></li>
</ul></li>
<li>
<ul>
<li>
<ul>
<li>SDK 3.1.3 &#8211; February 2010</li>
</ul></li>
</ul></li>
<li>SDK 3.2 &#8211; April 2010</li>
</ul>

<p>Major iPhone releases are spaced a year apart (with a few minor releases in-between) allowing developers to actually develop and release an app before the SDK changes.</p>

<p>The iPhone has another big advantage and it solves the problem of distribution as I alluded to earlier. iPhone users use iTunes to sync their devices and add content. The process of syncing the device also checks for updates and allows <em>all</em> iPhone OS devices (iPhones, iPod Touches, iPads) to download the latests version of the OS. As a result the March 2010 iPhone Platform Versions stats look very developer friendly:</p>

<p><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2010/05/Screen-shot-2010-05-20-at-4.01.22-PM.png" alt="" title="iPhone Platform Chart" width="439" height="310" class="aligncenter size-full wp-image-650" />
&#8212; <a href="http://metrics.admob.com/wp-content/uploads/2010/04/AdMob-Mobile-Metrics-Mar-10.pdf">Source</a></p>

<p>That&#8217;s only 5% of users who have NOT upgraded to at least 3.0 and 86% who are using one of the latest two (as of March) 3.1 minor versions. How great is that? Not only does 3.1 contain great features, I can actually use them and hit 86% of my users right away.</p>

<h2>The Result</h2>

<p>Recent trends are showing that Android OS based devices are passing Appleâ€™s iPhone OS devices to be the No. 2 smartphone operating system in the U.S.&#8212;After RIM&#8217;s Blackberry OS:</p>

<ul>
<li>RIMâ€™s BlackBerry OS at 36 percent;</li>
<li>Android at 28 percent;</li>
<li>Apple at 21 percent.</li>
</ul>

<p>&#8212;<a href="http://www.npd.com/press/releases/press_100510.html">source</a></p>

<p>I say as a developer I don&#8217;t care. The number of devices per OS is a great marketing number for Google and Apple to fight over but as a developer&#8212;who wants to get the most out of the SDK&#8212;I care about the <em>version</em> of the OS on the devices. If I want to use the latest and greatest SDK&#8217;s I&#8217;ll take Apple&#8217;s 80% of 21% over Google&#8217;s 30% of 28%.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/05/20/android-vs-iphone-development-decisions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>&#9734; Dissecting iPhone OS Touch Actions for Text</title>
		<link>http://jeffreysambells.com/posts/2010/04/30/dissecting-iphone-os-touch-actions-for-text/</link>
		<comments>http://jeffreysambells.com/posts/2010/04/30/dissecting-iphone-os-touch-actions-for-text/#comments</comments>
		<pubDate>Sat, 01 May 2010 01:41:18 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[XCode]]></category>
		<category><![CDATA[UITextInput]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=615</guid>
		<description><![CDATA[I&#8217;ve been working my way through a UiTextInput rich text editor implementation in iPhone OS 3.2 and thought I&#8217;d share some observations I&#8217;ve made regarding touch input related to text. One of the biggest hurdles with UiTextInput is that you don&#8217;t get the benefit of the great UI work that Apple has put in their [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working my way through a UiTextInput rich text editor implementation in iPhone OS 3.2 and thought I&#8217;d share some observations I&#8217;ve made regarding touch input related to text.</p>

<p>One of the biggest hurdles with UiTextInput is that you don&#8217;t get the benefit of the great UI work that Apple has put in their core iPhone text inputs. There&#8217;s no text selection, magnification loops, copy/paste or any of those other things we take for granted when we use the default inputs. If you want advanced editing features you have to implement them all yourself&#8212;and it&#8217;s a lot harder than it looks.</p>

<p>Text selection, for example, is something that you&#8217;re probably familiar with if you&#8217;ve used an iPhone or iPad but have you ever stopped to actually look what&#8217;s going on? The subtleties of the touch interaction are very intuitive but may not be what you expect when you think about it. For example, here are few things you may not have noticed when editing text in something like the default notepad.</p>

<ul>
<li><p>When you quickly single tap, the carat is placed in the text where you tapped but it&#8217;s position is based on word boundaries. A mouse click in a word processor places the carat at the point where you clicked but a tap in iPhone OS places it in front of or after the word, depending on which end of the word was nearest the tap.</p></li>
<li><p>Holding on a word will reveal a magnifying loop that gives you fine grained control over the selection. This is the <em>only</em> way you can place the carat within a word.</p></li>
<li><p>The select/select all/paste menu will appear if you long-tap. As a result it will always appear after the loop is shown but could also appear if you touch and release just before the loop shows (of course you&#8217;ll be selecting and pasting on a word boundary in the latter case).</p></li>
<li><p>The &#8220;select&#8221; option in the menu always starts by selecting a full word. Which word depends on where the carat is placed. If the carat is in a word then that word will be selected. If the carat is at the beginning of a word, between the space and the first letter, then the word following the carat is selected. If the carat is at the end of a word, before the following space, then the word preceding the carat is selected.</p></li>
<li><p>Double tapping a word will immediately select it. If you hold and drag on the second tap you can select a larger range based on where you drag. Interestingly, the range selection also has a magnifying loop&#8212;but with a different shape&#8212;so you can have fine grained control at the end of the selection.</p></li>
</ul>

<p>These are just a few of the subtle interactions that most iPhone users just do without thinking about.  If you&#8217;re going to implement your own UITextInput be sure to closely look at the existing text inputs and how you typically interact with them as you&#8217;ll need to implement yours the way users will expect it to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/04/30/dissecting-iphone-os-touch-actions-for-text/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>&#9734; Static Libraries with XCode and iPhone SDK</title>
		<link>http://jeffreysambells.com/posts/2010/04/16/static-libraries-with-xcode-and-iphone-sdk/</link>
		<comments>http://jeffreysambells.com/posts/2010/04/16/static-libraries-with-xcode-and-iphone-sdk/#comments</comments>
		<pubDate>Fri, 16 Apr 2010 21:30:09 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[XCode]]></category>
		<category><![CDATA[sdk]]></category>
		<category><![CDATA[static library]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=508</guid>
		<description><![CDATA[One of the easiest ways to overwhelm yourself when developing for iPhone OS is trying the all-in-one approach to code management. I&#8217;ve done it countless times and rooting through a maze of groups and files in a project can drive you insane. After frustration push me to the edge one too many times I finally [...]]]></description>
			<content:encoded><![CDATA[<p>One of the easiest ways to overwhelm yourself when developing for <a href="http://developer.apple.com/iphone">iPhone OS</a> is trying the all-in-one approach to code management. I&#8217;ve done it countless times and rooting through a maze of groups and files in a project can drive you insane. After frustration push me to the edge one too many times I finally snapped and sat down to figure out a better way.</p>

<p>When you have a large project, there&#8217;s often a lot of code that is very generic&#8212;an XML parser, network connection manager, location manager&#8212;that could be placed in their own shared libraries to use across different projects. This separation of code vastly increases the cleanliness of each individual project but also has other advantages including:</p>

<ul>
<li>Clear boundaries for business logic, api requirements, and unit testing.</li>
<li>Less overlap in a single project when multiple developers are working together.</li>
</ul>

<p>Moving the code to a library also removes it from the project with the &#8220;business logic&#8221;, allowing you to focus on the task at hand and prevent you from &#8220;tweaking&#8221; libraries just to accommodate the business logic of one particular project.</p>

<p>The iPhone SDK doesn&#8217;t support custom frameworks or dynamic libraries so you may not have thought it was possible but iPhone OS does does support <strong>static libraries</strong> and therefore allows you to write re-useable code&#8212;with a few caveats. This is how libraries such as <a href="http://www.flurry.com/">Flurry</a> or <a href="http://code.google.com/apis/analytics/docs/tracking/mobileAppsTracking.html">Google Mobile Analytics</a> work.</p>

<p>The only disadvantage is that if you include other frameworks or libraries in your library you still need to include them ALL in your final project. Adding <em>MapKit</em> to a static library means you also need to add MapKit directly to the main project (which is why you need to add the SQL lib with Google analytics).</p>

<p>Creating your own library requires a few steps but it boils down to:</p>

<ol>
<li>Create an XCode project to contain all the code for a specific library.</li>
<li>Create a static library target with the appropriate configuration.</li>
<li>Create a project that will use the library.</li>
<li>Import your static library project into your main project.</li>
<li>Link in the static library.</li>
</ol>

<p>To simplify steps one and two even further, I&#8217;ve created an <a href="http://jeffreysambells.com/iphone-os-static-library-template/">iPhone OS Static Library</a> Project template for XCode. Download it and feel free to suggest any changes you&#8217;d like to see.</p>

<p>Usage instructions and a quick &#8220;How To&#8221; are <a href="http://jeffreysambells.com/iphone-os-static-library-template/">available on the project page</a>.</p>

<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/04/16/static-libraries-with-xcode-and-iphone-sdk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9734; Android TextView with Auto Sized Content</title>
		<link>http://jeffreysambells.com/posts/2010/04/04/android-textview-with-auto-sized-content/</link>
		<comments>http://jeffreysambells.com/posts/2010/04/04/android-textview-with-auto-sized-content/#comments</comments>
		<pubDate>Mon, 05 Apr 2010 04:08:41 +0000</pubDate>
		<dc:creator>Jeffrey Sambells</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[TextView]]></category>

		<guid isPermaLink="false">http://jeffreysambells.com/?p=461</guid>
		<description><![CDATA[While working on an Android project lately I was looking for a solution to auto-size text in a TextView similar to the way the iPhone ADK allows you to select &#8220;fit text to box&#8221;. I couldn&#8217;t find any reference to something similar in the Android SDK so I had to roll my own TextView subclass. [...]]]></description>
			<content:encoded><![CDATA[<p>While working on an Android project lately I was looking for a solution to auto-size text in a <code>TextView</code> similar to the way the iPhone ADK allows you to select &#8220;fit text to box&#8221;. I couldn&#8217;t find any reference to something similar in the Android SDK so I had to roll my own <code>TextView</code> subclass.</p>

<p>Now all I have to do is call <code>setFitTextToBox(true)</code> on the <code>TextFitTextView</code> after allocation. Enjoy!</p>

<pre><code>public class TextFitTextView extends TextView {

    static final String TAG = "TextFitTextView";
    boolean fit = false;

    public TextFitTextView(Context context) {
        super(context);
    }

    public TextFitTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TextFitTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setFitTextToBox( Boolean fit ) {
        this.fit = fit;
    }

    protected void onDraw (Canvas canvas) {
        super.onDraw(canvas);
        if (fit) _shrinkToFit();
    }

    protected void _shrinkToFit() {

        int height = this.getHeight();
        int lines = this.getLineCount();
        Rect r = new Rect();
        int y1 = this.getLineBounds(0, r);
        int y2 = this.getLineBounds(lines-1, r);

        float size = this.getTextSize();
        if (y2 &gt; height &amp;&amp; size &gt;= 8.0f) {
            this.setTextSize(size - 2.0f);
            _shrinkToFit();
        }

    }
}
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://jeffreysambells.com/posts/2010/04/04/android-textview-with-auto-sized-content/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

