<?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>Current Working Directory</title>
	<atom:link href="http://www.cwd.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cwd.co.uk</link>
	<description>UK Android App &#38; Web Developers, based in Buckinghamshire near London.</description>
	<lastBuildDate>Thu, 08 Sep 2011 10:58:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>CircuitBee &#8211; An electronic schematic viewer for the web</title>
		<link>http://www.cwd.co.uk/2011/09/08/circuitbee-an-electronic-schematic-viewer-for-the-web/</link>
		<comments>http://www.cwd.co.uk/2011/09/08/circuitbee-an-electronic-schematic-viewer-for-the-web/#comments</comments>
		<pubDate>Thu, 08 Sep 2011 10:58:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[circuitbee]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=89</guid>
		<description><![CDATA[We&#8217;ve been very busy this year, as you may have noticed from the lack of updates here. CircuitBee (http://www.circuitbee.com) has been our main focus since earlier this year. Here&#8217;s a quick quote from our release post, describing the service and what it does: Have you ever designed an electronic schematic then wanted to share it ...]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve been very busy this year, as you may have noticed from the lack of updates here.</p>
<p>CircuitBee (<a href="http://www.circuitbee.com" title="CircuitBee">http://www.circuitbee.com</a>) has been our main focus since earlier this year. Here&#8217;s a quick quote from our release post, describing the service and what it does:</p>
<blockquote><p>
Have you ever designed an electronic schematic then wanted to share it on your blog? Or wanted help improving your circuit on a forum? Ever peered at a tiny/massive image of a circuit on a website and wondered why on earth there wasn’t a better alternative?</p>
<p>We have. Back in 2010 we were working on our first major electronics project, the Illuminatrix, an array of 256 RGB LEDs that were to show animations created by people all over the world at the Burning Man festival. It involved using a lot of technology we’d never used before, so we weren’t quite sure about our circuit designs.</p>
<p>We tried posting on blogs and forums trying to explain our schematic and the problems we were having with it. This proved more difficult than we expected: describing a circuit in words is really hard, so we tried to post an image of our schematic instead, and our schematic project files.</p>
<p>This involved a lot of messing around with capturing JPEGs of the schematic and uploading all the project’s symbol libraries and schematic files. But of course people willing to help didn’t necessarily have the right software, or the JPEG was too small  to read usefully, or too large to post on many of the forums. We thought that there must be a better way to share schematics, to discuss them, and to show them to people while writing about them. It turned out there wasn’t anything out there that would help us do this, so being the ambitious fools that we are we set out to create it.</p>
<p>CircuitBee is like YouTube for your circuit schematics. You upload  your Eagle or KiCAD schematics, we crunch the numbers and create an online embeddable version of your schematic.
</p></blockquote>
<p>Since our release just over a month ago the site has been doing very well. With over 2500 users registered, and 160 circuits uploaded the response from the community has been very encouraging. But, this is keeping us very busy, with lots to do, meetings to be had, and lots of users to respond to, we haven&#8217;t had much time to work on anything else. So, if we&#8217;re a little absent from the CWD site, then please head over to the <a href="http://www.cwd.co.uk/?webphys_portfolio=circuitbee" title="CircuitBee">CircuitBee site</a> to see what we&#8217;re up to!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/09/08/circuitbee-an-electronic-schematic-viewer-for-the-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A reusable BufferedInputStream</title>
		<link>http://www.cwd.co.uk/2011/05/06/a-reusable-bufferedinputstream/</link>
		<comments>http://www.cwd.co.uk/2011/05/06/a-reusable-bufferedinputstream/#comments</comments>
		<pubDate>Fri, 06 May 2011 16:17:06 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[BufferedInputStream]]></category>
		<category><![CDATA[garbage collection]]></category>
		<category><![CDATA[memory allocation]]></category>
		<category><![CDATA[optimisation]]></category>
		<category><![CDATA[ReusableBufferedInputStream]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=65</guid>
		<description><![CDATA[While working on a project for a client I ran into a performance issue that I&#8217;m sure many others have encountered also. I&#8217;m having to load a great many bitmaps dynamically, and as fast as possible to create a fluid user interface. We&#8217;re talking over 1000 bitmaps here, not all at once obviously, but a ...]]></description>
			<content:encoded><![CDATA[<p>While working on a project for a client I ran into a performance issue that I&#8217;m sure many others have encountered also.</p>
<p>I&#8217;m having to load a great many bitmaps dynamically, and as fast as possible to create a fluid user interface. We&#8217;re talking over 1000 bitmaps here, not all at once obviously, but a fair number at one time. I&#8217;m loading these files from SD card, so am creating the Bitmaps using the <em>BitmapFactory.decodeStream</em> method to stream them from file:</p>
<pre class="brush: java; title: ; notranslate">
...
InputStream is = new BufferedInputStream(new FileInputStream(myFile),8096);
Bitmap bmp = BitmapFactory.decodeStream(is,null,options);
...
</pre>
<p>In doing so I sensibly wrap my input stream in a <em>BufferedInputStream</em> so that I can more efficiently read the data. In fact internally the <em>decodeStream</em> method actually wraps your stream in a <em>BufferedInputStream</em> if you haven&#8217;t already. This would normally not be an issue. But since I&#8217;m loading many Bitmaps at once, and repeatedly, this is causing a memory allocation issue.</p>
<p>I noticed in my logcat a vast number of garbage collection calls which were drastically slowing down load times. After looking around my source, and the Android source, I concluded that this was due to each Bitmap I loaded caused a byte array to be allocated for the BufferedInputStream.</p>
<p>The solution? Simple really, I created a new class ReusableBufferedInputStream, included below, which is a duplication of the standard <a href="http://developer.android.com/reference/java/io/BufferedInputStream.html">BufferedInputStream</a> implementation you can find <a href="http://android.git.kernel.org/?p=platform/libcore.git;a=blob;f=luni/src/main/java/java/io/BufferedInputStream.java;hb=HEAD">here</a>. The only changes I&#8217;ve made have been to remove the normal constructors which take an input stream and a buffer size, and replace them with a constructor that lets you specify the actual byte array to use as the buffer. This stops the multiple allocations when loading many streams, and has drastically improved the performance of the application.</p>
<pre class="brush: java; title: ; notranslate">
/**
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the &quot;License&quot;); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * NOTICE: This class is a modification of the original BufferedInputStream
 * source code found at:
 *
 * http://android.git.kernel.org/?p=platform/libcore.git;a=blob;f=luni/src/main/java/java/io/BufferedInputStream.java;hb=HEAD
 *
 * Modifications have been made to allow buffers to be specified directly
 * thus avoiding memory allocations.
 *
 * Any questions/comments should be directed to ben@cwd.co.uk.
 */
package novoda.weeworld.assetpackmanager;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * A duplication of the {@link BufferedInputStream} class. The only difference being
 * this version allows a buffer to be specified directly. This can be used to very
 * effectively avoid repeated allocations of buffers. Thus massively increasing
 * performance by eliminating garbage collection.
 *
 * The following is from the BufferedInputStream documentation:
 *
 * Wraps an existing {@link InputStream} and &lt;em&gt;buffers&lt;/em&gt; the input.
 * Expensive interaction with the underlying input stream is minimized, since
 * most (smaller) requests can be satisfied by accessing the buffer alone. The
 * drawback is that some extra space is required to hold the buffer and that
 * copying takes place when filling that buffer, but this is usually outweighed
 * by the performance benefits.
 *
 * &lt;p/&gt;A typical application pattern for the class looks like this:&lt;p/&gt;
 *
 * &lt;pre&gt;
 * byte[] myBuffer = new byte[16*1024];
 * ReusableBufferedInputStream buf = new ReusableBufferedInputStream(new FileInputStream(&amp;quot;file.java&amp;quot;),myBuffer);
 * &lt;/pre&gt;
 *
 * @see BufferedInputStream
 */
public class ReusableBufferedInputStream extends FilterInputStream {
    /**
     * The buffer containing the current bytes read from the target InputStream.
     */
    protected volatile byte[] buf;

    /**
     * The total number of bytes inside the byte array {@code buf}.
     */
    protected int count;

    /**
     * The current limit, which when passed, invalidates the current mark.
     */
    protected int marklimit;

    /**
     * The currently marked position. -1 indicates no mark has been set or the
     * mark has been invalidated.
     */
    protected int markpos = -1;

    /**
     * The current position within the byte array {@code buf}.
     */
    protected int pos;

    /**
     * Constructs a new {@code ReusableBufferedInputStream}, providing {@code in} with a buffer
     * of 8192 bytes.
     *
     * &lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; passing a null source creates a closed
     * {@code BufferedInputStream}. All read operations on such a stream will
     * fail with an IOException.
     *
     * @param in the {@code InputStream} the buffer reads from.
     * @param buffer {@code byte[]} to use as the buffer.
     */
    public ReusableBufferedInputStream(InputStream in, byte[] buffer) {
        super(in);
        if (buffer==null) {
        	throw new NullPointerException(&quot;Buffer argument is null&quot;);
        }
        buf = buffer;
    }

    /**
     * Returns an estimated number of bytes that can be read or skipped without blocking for more
     * input. This method returns the number of bytes available in the buffer
     * plus those available in the source stream, but see {@link InputStream#available} for
     * important caveats.
     *
     * @return the estimated number of bytes available
     * @throws IOException if this stream is closed or an error occurs
     */
    @Override
    public synchronized int available() throws IOException {
        InputStream localIn = in; // 'in' could be invalidated by close()
        if (buf == null || localIn == null) {
            throw streamClosed();
        }
        return count - pos + localIn.available();
    }

    private IOException streamClosed() throws IOException {
        throw new IOException(&quot;ReusableBufferedInputStream is closed&quot;);
    }

    /**
     * Closes this stream. The source stream is closed and any resources
     * associated with it are released.
     *
     * @throws IOException
     *             if an error occurs while closing this stream.
     */
    @Override
    public void close() throws IOException {
        buf = null;
        InputStream localIn = in;
        in = null;
        if (localIn != null) {
            localIn.close();
        }
    }

    private int fillbuf(InputStream localIn, byte[] localBuf)
            throws IOException {
        if (markpos == -1 || (pos - markpos &gt;= marklimit)) {
            // Mark position not set or exceeded readlimit
            int result = localIn.read(localBuf);
            if (result &gt; 0) {
                markpos = -1;
                pos = 0;
                count = result == -1 ? 0 : result;
            }
            return result;
        }
        if (markpos == 0 &amp;&amp; marklimit &gt; localBuf.length) {
            // Increase buffer size to accommodate the readlimit
            int newLength = localBuf.length * 2;
            if (newLength &gt; marklimit) {
                newLength = marklimit;
            }
            byte[] newbuf = new byte[newLength];
            System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length);
            // Reassign buf, which will invalidate any local references
            // FIXME: what if buf was null?
            localBuf = buf = newbuf;
        } else if (markpos &gt; 0) {
            System.arraycopy(localBuf, markpos, localBuf, 0, localBuf.length
                    - markpos);
        }
        // Set the new position and mark position
        pos -= markpos;
        count = markpos = 0;
        int bytesread = localIn.read(localBuf, pos, localBuf.length - pos);
        count = bytesread &lt;= 0 ? pos : pos + bytesread;
        return bytesread;
    }

    /**
     * Sets a mark position in this stream. The parameter {@code readlimit}
     * indicates how many bytes can be read before a mark is invalidated.
     * Calling {@code reset()} will reposition the stream back to the marked
     * position if {@code readlimit} has not been surpassed. The underlying
     * buffer may be increased in size to allow {@code readlimit} number of
     * bytes to be supported.
     *
     * @param readlimit
     *            the number of bytes that can be read before the mark is
     *            invalidated.
     * @see #reset()
     */
    @Override
    public synchronized void mark(int readlimit) {
        marklimit = readlimit;
        markpos = pos;
    }

    /**
     * Indicates whether {@code ReusableBufferedInputStream} supports the {@code mark()}
     * and {@code reset()} methods.
     *
     * @return {@code true} for ReusableBufferedInputStreams.
     * @see #mark(int)
     * @see #reset()
     */
    @Override
    public boolean markSupported() {
        return true;
    }

    /**
     * Reads a single byte from this stream and returns it as an integer in the
     * range from 0 to 255. Returns -1 if the end of the source string has been
     * reached. If the internal buffer does not contain any available bytes then
     * it is filled from the source stream and the first byte is returned.
     *
     * @return the byte read or -1 if the end of the source stream has been
     *         reached.
     * @throws IOException
     *             if this stream is closed or another IOException occurs.
     */
    @Override
    public synchronized int read() throws IOException {
        // Use local refs since buf and in may be invalidated by an
        // unsynchronized close()
        byte[] localBuf = buf;
        InputStream localIn = in;
        if (localBuf == null || localIn == null) {
            throw streamClosed();
        }

        // Are there buffered bytes available?
        if (pos &gt;= count &amp;&amp; fillbuf(localIn, localBuf) == -1) {
            return -1; // no, fill buffer
        }
        // localBuf may have been invalidated by fillbuf
        if (localBuf != buf) {
            localBuf = buf;
            if (localBuf == null) {
                throw streamClosed();
            }
        }

        // Did filling the buffer fail with -1 (EOF)?
        if (count - pos &gt; 0) {
            return localBuf[pos++] &amp; 0xFF;
        }
        return -1;
    }

    /**
     * Reads at most {@code length} bytes from this stream and stores them in
     * byte array {@code buffer} starting at offset {@code offset}. Returns the
     * number of bytes actually read or -1 if no bytes were read and the end of
     * the stream was encountered. If all the buffered bytes have been used, a
     * mark has not been set and the requested number of bytes is larger than
     * the receiver's buffer size, this implementation bypasses the buffer and
     * simply places the results directly into {@code buffer}.
     *
     * @param buffer
     *            the byte array in which to store the bytes read.
     * @param offset
     *            the initial position in {@code buffer} to store the bytes read
     *            from this stream.
     * @param length
     *            the maximum number of bytes to store in {@code buffer}.
     * @return the number of bytes actually read or -1 if end of stream.
     * @throws IndexOutOfBoundsException
     *             if {@code offset &lt; 0} or {@code length &lt; 0}, or if
     *             {@code offset + length} is greater than the size of
     *             {@code buffer}.
     * @throws IOException
     *             if the stream is already closed or another IOException
     *             occurs.
     */
    @Override
    public synchronized int read(byte[] buffer, int offset, int length) throws IOException {
        // Use local ref since buf may be invalidated by an unsynchronized
        // close()
        byte[] localBuf = buf;
        if (localBuf == null) {
            throw streamClosed();
        }
        // avoid int overflow
        // BEGIN android-changed
        // Exception priorities (in case of multiple errors) differ from
        // RI, but are spec-compliant.
        // made implicit null check explicit, used (offset | length) &lt; 0
        // instead of (offset &lt; 0) || (length &lt; 0) to safe one operation
        if (buffer == null) {
            throw new NullPointerException(&quot;buffer == null&quot;);
        }
        if ((offset | length) &lt; 0 || offset &gt; buffer.length - length) {
            throw new IndexOutOfBoundsException();
        }
        // END android-changed
        if (length == 0) {
            return 0;
        }
        InputStream localIn = in;
        if (localIn == null) {
            throw streamClosed();
        }

        int required;
        if (pos &lt; count) {
            // There are bytes available in the buffer.
            int copylength = count - pos &gt;= length ? length : count - pos;
            System.arraycopy(localBuf, pos, buffer, offset, copylength);
            pos += copylength;
            if (copylength == length || localIn.available() == 0) {
                return copylength;
            }
            offset += copylength;
            required = length - copylength;
        } else {
            required = length;
        }

        while (true) {
            int read;
            //
            // If we're not marked and the required size is greater than the
            // buffer, simply read the bytes directly bypassing the buffer.
            //
            if (markpos == -1 &amp;&amp; required &gt;= localBuf.length) {
                read = localIn.read(buffer, offset, required);
                if (read == -1) {
                    return required == length ? -1 : length - required;
                }
            } else {
                if (fillbuf(localIn, localBuf) == -1) {
                    return required == length ? -1 : length - required;
                }
                // localBuf may have been invalidated by fillbuf
                if (localBuf != buf) {
                    localBuf = buf;
                    if (localBuf == null) {
                        throw streamClosed();
                    }
                }

                read = count - pos &gt;= required ? required : count - pos;
                System.arraycopy(localBuf, pos, buffer, offset, read);
                pos += read;
            }
            required -= read;
            if (required == 0) {
                return length;
            }
            if (localIn.available() == 0) {
                return length - required;
            }
            offset += read;
        }
    }

    /**
     * Resets this stream to the last marked location.
     *
     * @throws IOException
     *             if this stream is closed, no mark has been set or the mark is
     *             no longer valid because more than {@code readlimit} bytes
     *             have been read since setting the mark.
     * @see #mark(int)
     */
    @Override
    public synchronized void reset() throws IOException {
        // BEGIN android-changed
        //
        // These exceptions get thrown in some &quot;normalish&quot; circumstances,
        // so it is preferable to avoid loading up the whole big set of
        // messages just for these cases.
        //
        if (buf == null) {
            throw new IOException(&quot;Stream is closed&quot;);
        }
        if (-1 == markpos) {
            throw new IOException(&quot;Mark has been invalidated.&quot;);
        }
        // END android-changed
        pos = markpos;
    }

    /**
     * Skips {@code amount} number of bytes in this stream. Subsequent
     * {@code read()}'s will not return these bytes unless {@code reset()} is
     * used.
     *
     * @param amount
     *            the number of bytes to skip. {@code skip} does nothing and
     *            returns 0 if {@code amount} is less than zero.
     * @return the number of bytes actually skipped.
     * @throws IOException
     *             if this stream is closed or another IOException occurs.
     */
    @Override
    public synchronized long skip(long amount) throws IOException {
        // Use local refs since buf and in may be invalidated by an
        // unsynchronized close()
        byte[] localBuf = buf;
        InputStream localIn = in;
        if (localBuf == null) {
            throw streamClosed();
        }
        if (amount &lt; 1) {
            return 0;
        }
        if (localIn == null) {
            throw streamClosed();
        }

        if (count - pos &gt;= amount) {
            pos += amount;
            return amount;
        }
        long read = count - pos;
        pos = count;

        if (markpos != -1) {
            if (amount &lt;= marklimit) {
                if (fillbuf(localIn, localBuf) == -1) {
                    return read;
                }
                if (count - pos &gt;= amount - read) {
                    pos += amount - read;
                    return amount;
                }
                // Couldn't get all the bytes, skip what we read
                read += (count - pos);
                pos = count;
                return read;
            }
        }
        return read + localIn.skip(amount - read);
    }
}
</pre>
<p>You can then use this new class like so:</p>
<pre class="brush: java; title: ; notranslate">
...
// allocate a buffer we'll reuse
byte[] reusableBuffer = new byte[16*1024];
...
InputStream is = new ReusableBufferedInputStream(new FileInputStream(myFile),reusableBuffer);
Bitmap bmp = BitmapFactory.decodeStream(is,null,options);
...
</pre>
<p>I take no credit for the implementation of this class (its just a copy and paste job, since I want the same functionality), I only added the new constructor and name. I have to say, having the source code for Android available for me to browse through has really helped me optimise my apps lately. I hope this little post proves useful to somebody.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/05/06/a-reusable-bufferedinputstream/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Unicode Keyboard Released!</title>
		<link>http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/</link>
		<comments>http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/#comments</comments>
		<pubDate>Wed, 04 May 2011 14:36:36 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[unicode keyboard]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=56</guid>
		<description><![CDATA[Last weekend we got bored during the royal wedding, so decided to fix a problem related to hot beverages. Today we finished polishing off our Unicode Keyboard and released it on the Android Market for 99p or thereabouts. This supplementary keyboard lets you input any Unicode character or symbol on your Android device directly. Without ...]]></description>
			<content:encoded><![CDATA[<p>Last weekend we got bored during the royal wedding, so decided to fix a problem related to <a title="Hot Beverage (or the start of the Unicode Keyboard)" href="http://www.cwd.co.uk/2011/04/29/hot-beverage-or-the-start-of-the-unicode-keyboard/">hot beverages</a>.</p>
<p>Today we finished polishing off our <a title="Unicode Keyboard on Android Market" href="http://market.android.com/details?id=uk.co.cwd.unicodekeyboard">Unicode Keyboard</a> and released it on the Android Market for 99p or thereabouts. This supplementary keyboard lets you input any Unicode character or symbol on your Android device directly. Without having to copy and paste or switch applications or any of that nonsense.</p>
<p>Need a character? Perhaps you want to tweet your latest chess move? (♜ to ♕3) or confess your undying ♥ for ☃. Then you need Unicode Keyboard. When ever you need a Unicode character simply switch your input method to the keyboard. You can then dial in the character you want, select from recently used symbols, or browse or search the entire range of Unicode. Once you&#8217;ve inserted the symbols you want, hit the handy key to switch back to your other input methods.</p>
<p>We hope you like it, here&#8217;s some screenshots, and you can find it on the Android Market <a title="Unicode Keyboard on the Android Market" href="http://market.android.com/details?id=uk.co.cwd.unicodekeyboard">here</a>.</p>

<a href='http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/browse_list/' title='Unicode Keyboard - Browse Dialog' rel='gallery-56'><img width="150" height="150" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/browse_list-150x150.png" class="attachment-thumbnail" alt="Drill down through the different Unicode blocks to find the characters you want." title="Unicode Keyboard - Browse Dialog" /></a>
<a href='http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/main/' title='Unicode Keyboard' rel='gallery-56'><img width="150" height="150" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/main-150x150.png" class="attachment-thumbnail" alt="Dial in the character you want, or use the recently used symbols!" title="Unicode Keyboard" /></a>
<a href='http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/main_land/' title='Unicode Keyboard in Landscape' rel='gallery-56'><img width="150" height="150" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/main_land-150x150.png" class="attachment-thumbnail" alt="Unicode Keyboard in Landscape" title="Unicode Keyboard in Landscape" /></a>
<a href='http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/search/' title='Unicode Keyboard - Search' rel='gallery-56'><img width="150" height="150" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/search-150x150.png" class="attachment-thumbnail" alt="Search all of Unicode for the character you want" title="Unicode Keyboard - Search" /></a>
<a href='http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/search_land/' title='Unicode Keyboard - Search Landscape' rel='gallery-56'><img width="150" height="150" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/search_land-150x150.png" class="attachment-thumbnail" alt="Unicode Keyboard - Search Landscape" title="Unicode Keyboard - Search Landscape" /></a>
<a href='http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/symbols/' title='Unicode Keyboard - Symbols' rel='gallery-56'><img width="150" height="150" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/symbols-150x150.png" class="attachment-thumbnail" alt="Select the character you want by browsing through them." title="Unicode Keyboard - Symbols" /></a>

<p>Oh and we documented our build, so you can read about how we did it in these posts:</p>
<ul>
<li><a title="The making of Unicode Keyboard #1" href="http://www.cwd.co.uk/2011/04/29/the-making-of-unicode-keyboard-1/">Making of Unicode Keyboard #1</a></li>
<li><a title="The making of Unicode Keyboard #2" href="http://www.cwd.co.uk/2011/04/30/the-making-of-unicode-keyboard-2/">Making of Unicode Keyboard #2</a></li>
<li><a title="The making of Unicode Keyboard #3" href="http://www.cwd.co.uk/2011/05/01/the-making-of-unicode-keyboard-3/">Making of Unicode Keyboard #3</a></li>
<li><a title="The making of Unicode Keyboard #4" href="http://www.cwd.co.uk/2011/05/02/the-making-of-unicode-keyboard-4/">Making of Unicode Keyboard #4</a></li>
</ul>
<p>&nbsp;</p>
<p>Let us know what you think in the comments, and be sure to rate it on the Market!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/05/04/unicode-keyboard-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The making of Unicode Keyboard #4</title>
		<link>http://www.cwd.co.uk/2011/05/02/the-making-of-unicode-keyboard-4/</link>
		<comments>http://www.cwd.co.uk/2011/05/02/the-making-of-unicode-keyboard-4/#comments</comments>
		<pubDate>Mon, 02 May 2011 13:01:06 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[unicode keyboard]]></category>
		<category><![CDATA[dialog]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[window]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=55</guid>
		<description><![CDATA[This will be the final post in the series. This project has taken us on a merry little tour of Android features this weekend. The Unicode Keyboard now functions, and its starting to look more polished. Much of that we will finish off today and tomorrow before we release it hopefully in the middle of ...]]></description>
			<content:encoded><![CDATA[<p>This will be the final post in the series. This project has taken us on a merry little tour of Android features this weekend. The Unicode Keyboard now functions, and its starting to look more polished. Much of that we will finish off today and tomorrow before we release it hopefully in the middle of this week. In this post we just wanted to show the solution to a little problem with dialogs shown from within a keyboard.</p>
<p>The keyboard is an implementation of an <em>InputMethodService</em> (often known as an IME). The keyboard runs as service, as such it doesn&#8217;t have ordinary windowing setup. So when you try and launch a dialog, you get a big fat NullPointerException related to a Window. This exception isn&#8217;t all that helpful since it seems unrelated to the dialog being shown.</p>
<p>It is of course due to the fact that you&#8217;re launching it from what is essentially a service. In order to make our dialog work we need to give its window the appropriate type and make it focusable. This can be done quite easily with the following snippet:</p>
<pre class="brush: java; title: ; notranslate">
    	Window window = dialog.getWindow();
    	WindowManager.LayoutParams lp = window.getAttributes();
    	lp.height = WindowManager.LayoutParams.FILL_PARENT;
    	lp.width = WindowManager.LayoutParams.FILL_PARENT;
    	lp.token = this.mInputView.getWindowToken();
    	lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
    	window.setAttributes(lp);
    	window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

    	dialog.show();
</pre>
<p>With this fix we could finally show dialogs from within an IME. This made it possible for us to show a popup dialog letting you browse all the code blocks within Unicode and select characters that way.</p>
<p>In order to do this we showed a view in the dialog that contained a ViewFlipper holding two ListViews. The first ListView showed all the code blocks retrieved from the database, when clicked we flipped the view to show the second ListView. This view was populated with an adapter containing all the characters retrieved from the database in the selected code block range. This made for a nice interface since we could switch back and forth between the two views and keep our place within the code blocks list allowing for a smooth browsing experience. I&#8217;ll go into exactly how all that is implemented if necessary, but I think ListViews and Adapters have been covered to death online already.</p>
<p>So it just remains for us to polish off the fine details, improve the styling a little, and create the relevant Android Market assets. Hopefully we&#8217;ll release this by Wednesday this week. Stay tuned for a post with screenshots of the final product.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/05/02/the-making-of-unicode-keyboard-4/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The making of Unicode Keyboard #3</title>
		<link>http://www.cwd.co.uk/2011/05/01/the-making-of-unicode-keyboard-3/</link>
		<comments>http://www.cwd.co.uk/2011/05/01/the-making-of-unicode-keyboard-3/#comments</comments>
		<pubDate>Sun, 01 May 2011 15:57:14 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[unicode keyboard]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[sqlite]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=53</guid>
		<description><![CDATA[So we&#8217;ve covered how to make an alternative keyboard layout, how to intercept the key presses from our keyboard and send them where necessary, and how to send characters to the view being edited. The keyboard is functional, it just needs polishing up now. In order to do that, we really want to know what ...]]></description>
			<content:encoded><![CDATA[<p>So we&#8217;ve covered how to make an <a title="The making of Unicode Keyboard #1" href="http://www.cwd.co.uk/2011/04/29/the-making-of-unicode-keyboard-1/">alternative keyboard layout</a>, how to<a title="The making of Unicode Keyboard #2" href="http://www.cwd.co.uk/2011/04/30/the-making-of-unicode-keyboard-2/"> intercept the key presses</a> from our keyboard and send them where necessary, and how to send characters to the view being edited. The keyboard is functional, it just needs polishing up now.</p>
<p>In order to do that, we really want to know what characters are being entered as the Unicode range is huge and users can&#8217;t be expected to remember all those hex codes. So we created a database of all the Unicode codepoints, and inserted that into our application and used it to lookup the codes as they were entered to get the textual name of the dialed in character. This is also helpful since the default Android fonts don&#8217;t support most of Unicode and characters show up as square blocks, so its nice to show users what they&#8217;re entering when they can&#8217;t actually see it.</p>
<p>Thankfully Unicode provide various files describing all the characters, we used one they call <a title="Unicode 6 NamesList" href="http://www.unicode.org/Public/6.0.0/ucd/NamesList.txt">NamesList</a>. This describes all the characters and their alternative names. Obviously we can&#8217;t use this file as-is, so we converted it into a CSV file that can be imported into an SQLite database. This turned out to be a relatively straightforward task. In fact our resident tester, designer, grumbler and general odd-job-man Ted managed to code this up in PHP in a few hours and he claims not to be able to code at all!</p>
<p>We ended up arranging our CSV file with the integer value of the codepoint for the character, followed by the official name for the character, then the alternative names all separated by tabs:</p>
<pre class="brush: plain; first-line: 117; title: ; notranslate">
...
117    LATIN SMALL LETTER U
118    LATIN SMALL LETTER V
119    LATIN SMALL LETTER W
120    LATIN SMALL LETTER X
121    LATIN SMALL LETTER Y
122    LATIN SMALL LETTER Z
123    LEFT CURLY BRACKET    OPENING CURLY BRACKET, left brace, opening curly bracket
124    VERTICAL LINE    VERTICAL BAR, vertical bar
125    RIGHT CURLY BRACKET    CLOSING CURLY BRACKET, right brace, closing curly bracket
126    TILDE
...
</pre>
<p>This format is rather handy, since we can just import it directly into an SQLite database. Due to the integer field being first we can also use this as the primary key for our table, that makes lookups really fast. For our app we&#8217;ve also converted the <a title="Unicode Blocks" href="http://www.unicode.org/Public/6.0.0/ucd/Blocks.txt">Blocks</a> file into a similar format so that we can have a list of all the code blocks within Unicode to make our browsing experience nicer.</p>
<p>If you haven&#8217;t got SQLite yet you should go <a title="SQLite download" href="http://www.sqlite.org/download.html">download it here</a>. We used the following commands to create our database tables and import our data:</p>
<pre class="brush: plain; title: ; notranslate">

CREATE TABLE codepoints (_id INTEGER PRIMARY KEY, name TEXT NOT NULL);
CREATE TABLE codeblocks (_id INTEGER PRIMARY KEY, name TEXT NOT NULL, lowerRange INTEGER NOT NULL, upperRange INTEGER NOT NULL);
 CREATE TABLE &quot;android_metadata&quot; (&quot;locale&quot; TEXT DEFAULT 'en_US');
INSERT INTO &quot;android_metadata&quot; VALUES ('en_US');
.separator \t
.import UnicodeData.csv codepoints
.import UnicodeBlocks.csv codeblocks
</pre>
<p>Couple of things to note here, we named our primary key fields &#8216;<em>_id</em>&#8216;, thats to make it compatible with Android since it will look for this field in our tables. We&#8217;ve also added an &#8216;<em>android_metadata</em>&#8216; table, this is also required by Android. We&#8217;ve then set the separator and imported our CSV files into our tables. We now have a database of all the Unicode information we need to create a nice browse and search experience.</p>
<p>Next up we needed to add our database as an asset for our application, and have it copied into place when our app starts for the first time. There&#8217;s a handy little class called <em>SQLiteOpenHelper</em> which we&#8217;re going to extend to do most of our database access, and we&#8217;ll add our copy behaviour to that. <em>Juan-Manuel Fluxà</em> made this <a title="Using your own SQLite database in Android applications" href="http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/">great post</a> about how to extend this class to copy databases from your assets folder. We based most of our database code off this so go take a look, but we did find we had to fix one small issue. Before each call to <em>getReadableDatabase()</em> in his class we added a call to <em>close()</em>. This fixes a rather odd bug that crops up on first installation of the database, it appears something ends up in an incorrect state causing an exception, but a quick call to close fixes that.</p>
<p>So when our keyboard is started, we need to copy over the database if necessary, and open up a connection to it. We added a call to <em>createDatabase</em> and <em>openDatabase</em> in our <em>onCreate</em> method to accomplish this:</p>
<pre class="brush: java; highlight: [4,5,6,7,8,9,10,11,12,13]; title: ; notranslate">
    @Override public void onCreate() {
        super.onCreate();
        mWordSeparators = getResources().getString(R.string.word_separators);
        dbHelper = new DatabaseHelper(this);

        try {

        	dbHelper.createDataBase();

        	dbHelper.openDataBase();
	 	} catch (IOException ioe) {
	 		throw new Error(&quot;Unable to create database&quot;);
	 	}
    }
</pre>
<p>We also added some methods to our database helper that let us search and list entries from the database. This seemed like a convenient place to store these, and they&#8217;re relatively simple queries :</p>
<pre class="brush: java; title: ; notranslate">
    public String getName(int codepoint) {
    	Cursor cursor = myDataBase.query(TABLE, new String[] { &quot;_id&quot;, &quot;name&quot; }, &quot;_id = &quot; + String.valueOf(codepoint), null, null, null, null);
    	if (cursor.moveToFirst()) {
    		return cursor.getString(1);
    	}
    	return &quot;Unknown&quot;;
    }
    public ArrayList&lt;CodeBlock&gt; getCodeBlocks() {
    	ArrayList&lt;CodeBlock&gt; codeBlocks = new ArrayList&lt;CodeBlock&gt;();

    	Cursor cursor = myDataBase.query(BLOCKSTABLE, new String[] { &quot;_id&quot;, &quot;name&quot;, &quot;lowerRange&quot;, &quot;upperRange&quot; }, null, null, null, null, null);
    	if (cursor.moveToFirst()) {
    		do {
    			CodeBlock newBlock = new CodeBlock();
    			newBlock.id = cursor.getInt(0);
    			newBlock.name = cursor.getString(1);
    			newBlock.lowerRange = cursor.getInt(2);
    			newBlock.upperRange = cursor.getInt(3);
    			codeBlocks.add(newBlock);
    		} while (cursor.moveToNext());
    	}
    	return codeBlocks;
    }

    public ArrayList&lt;CodePoint&gt; getCodePoints(int lowerRange, int upperRange) {
    	ArrayList&lt;CodePoint&gt; codePoints = new ArrayList&lt;CodePoint&gt;();

    	Cursor cursor = myDataBase.query(TABLE, new String[] { &quot;_id&quot;, &quot;name&quot; }, &quot;_id &gt;= &quot; + String.valueOf(lowerRange) + &quot; AND _id &lt;= &quot; + String.valueOf(upperRange), null, null, null, null);
    	if (cursor.moveToFirst()) {
    		do {
    			CodePoint newPoint= new CodePoint();
    			newPoint.codepoint = cursor.getInt(0);
    			newPoint.name = cursor.getString(1);
    			codePoints.add(newPoint);
    		} while (cursor.moveToNext());
    	}
    	return codePoints;
    }
</pre>
<p>These let us list our entries from the codeblocks database, and lookup entries from the relevant ranges as well as lookup individual codepoints. We added added a call to the <em>getName()</em> method to our <em>handleHexChar</em> method so that we could lookup the character every time we dialled in a new character:</p>
<pre class="brush: java; highlight: [19,20]; title: ; notranslate">
private void handleHexChar(int code) {
    // if the character is a hex character append the char to our existing value
    if (isHexChar(code)) {
        // codepoint stores our currently dialled in number
        String hex = Integer.toHexString(this.codepoint);
        if (hex.length() &gt;= 5) {
            // only want to enter up to 5 hex characters
            return;
        }
        hex += String.valueOf((char)code);
        // convert back into an integer
        this.codepoint = Integer.parseInt(hex,16);
        // uppercase for display purposes
        hex = hex.toUpperCase();
        // convert codepoint into an actual unicode character as a string
        int[] cp = {codepoint};
        String s = new String(cp,0,1);

        // lookup the name for the character
    	String name = dbHelper.getName(codepoint);

        // add the unicode character onto our string for display in the preview area
        // output in the form 'U+2605 ★ Black Star'
        this.mPreviewView.setText(&quot;U+&quot; + hex + &quot; &quot; + s + &quot; &quot; + name);
    }
}
</pre>
<p>So I guess that covers the basics of how to setup a working SQLite database from a pre-existing asset. We now have a working keyboard and can now see what character we&#8217;re entering even though Unicode support on Android is patchy at best. In the next post we&#8217;re going to cover something slightly more tricky, showing dialogs within a keyboard, this proved non-trivial as the keyboard isn&#8217;t your standard activity and so doesn&#8217;t behave quite the same when showing dialogs. More on that next time&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/05/01/the-making-of-unicode-keyboard-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The making of Unicode Keyboard #2</title>
		<link>http://www.cwd.co.uk/2011/04/30/the-making-of-unicode-keyboard-2/</link>
		<comments>http://www.cwd.co.uk/2011/04/30/the-making-of-unicode-keyboard-2/#comments</comments>
		<pubDate>Sat, 30 Apr 2011 12:10:02 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[unicode keyboard]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=51</guid>
		<description><![CDATA[So yesterday we detailed some of the issues surrounding showing extra user interface views around a normal keyboard in Android. Obviously we could have built the entire KeyboardView from scratch, but the one that ships with the SDK does a lot of stuff and we&#8217;re trying to get this project built as simply as possible. ...]]></description>
			<content:encoded><![CDATA[<p>So <a title="The making of Unicode Keyboard #1" href="http://www.cwd.co.uk/2011/04/29/the-making-of-unicode-keyboard-1/">yesterday</a> we detailed some of the issues surrounding showing extra user interface views around a normal keyboard in Android. Obviously we could have built the entire KeyboardView from scratch, but the one that ships with the SDK does a lot of stuff and we&#8217;re trying to get this project built as simply as possible.</p>
<p>Today we&#8217;re going to attempt to get the new UI we&#8217;ve made to send its keypresses to our own EditText area in which we will show the currently dialed in Unicode character.</p>
<p>Normally keypresses from the Keyboard end up going to the <em>SoftKeyboard.onKey</em> method which then passes them off to various other functions such as <em>handleBackspace</em> or <em>handleCharacter</em>. Thats all well and good for most normal keyboards. For a Unicode Keyboard however we want to dial in a Unicode codepoint (e.g. U+2605) and then when we have selected the right character we want to send it to the editing view.</p>
<pre class="brush: java; title: ; notranslate">
    public void onKey(int primaryCode, int[] keyCodes) {
    	if (this.mCurKeyboard == this.mUnicodeKeyboard &amp;amp;&amp;amp; primaryCode != 10) {
    		// send the key to the unicode preview view and build up our codepoint
    		handleUnicode(primaryCode);
    		return;
    	}
        // continue with previous implementation
        ...
    }
</pre>
<p>In this snippet we&#8217;ve detected when we&#8217;re using the unicode keyboard view, and sent our characters off to another function: <em>handleUnicode</em>. Note we&#8217;ve detected the case of hitting the &#8216;Enter&#8217; key (keycode == 10) however, and are going to send that one through the normal functionality. Thats so that the Enter key still moves us between input boxes as a normal keyboard would. Here&#8217;s our implementation for the <em>handleUnicode</em> function.</p>
<pre class="brush: java; title: ; notranslate">
    private void handleHexChar(int code) {
    	// if the character is a hex character append the char to our existing value
    	if (isHexChar(code)) {
            // codepoint stores our currently dialled in number
        	String hex = Integer.toHexString(this.codepoint);
	    	if (hex.length() &amp;gt;= 5) {
                // only want to enter up to 5 hex characters
	    		return;
	    	}
	    	hex += String.valueOf((char)code);
	    	// convert back into an integer
	    	this.codepoint = Integer.parseInt(hex,16);
            // uppercase for display purposes
    	    hex = hex.toUpperCase();
            // convert codepoint into an actual unicode character as a string
            int[] cp = {codepoint};
            String s = new String(cp,0,1);
            // add the unicode character onto our string for display in the preview area
            // output in the form 'U+2605 ★'
            this.mPreviewView.setText(&amp;quot;U+&amp;quot; + hex + &amp;quot; &amp;quot; + s);
    	}
    }
</pre>
<p>Now when we tap the keys on our unicode keyboard, they should get sent to our EditText area (mPreviewArea) and allow us to select our Unicode codepoint. Next we need to make the send button functional, so we&#8217;ll add an <em>onClickListener</em> to our <em>onCreateInputView</em> function for the button and point it to our <em>sendUnicode</em> function.</p>
<pre class="brush: java; title: ; notranslate">
    private void sendUnicode(int codepoint) {
    	int[] cp = {codepoint};
    	String s = new String(cp,0,1);
        // getCurrentInputConnection returns a connection through which we can send
        // the character to the editing view
    	this.getCurrentInputConnection().commitText(s, 1);
    }
</pre>
<p>We now have a functional keyboard! We can dial in characters and send them to our editing view.</p>
<p>In the next post we&#8217;ll start looking at how we&#8217;re going to browse the list of unicode characters so we don&#8217;t have to remember the codepoints. We&#8217;ll back the keyboard with an SQLite database, and use this to lookup the names of our characters as we dial them in as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/04/30/the-making-of-unicode-keyboard-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The making of Unicode Keyboard #1</title>
		<link>http://www.cwd.co.uk/2011/04/29/the-making-of-unicode-keyboard-1/</link>
		<comments>http://www.cwd.co.uk/2011/04/29/the-making-of-unicode-keyboard-1/#comments</comments>
		<pubDate>Fri, 29 Apr 2011 17:29:53 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[unicode keyboard]]></category>
		<category><![CDATA[IME]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=47</guid>
		<description><![CDATA[So today we want to start building an Android IME (InputMethod) implementation that lets us input Unicode characters on our Android device. What does that mean exactly? First off, I&#8217;m going to assume you know what Unicode is. If you don&#8217;t then head over here to read a great explanation from the people that manage ...]]></description>
			<content:encoded><![CDATA[<p>So today we want to start building an Android IME (<strong>I</strong>nput<strong>Me</strong>thod) implementation that lets us input Unicode characters on our Android device. What does that mean exactly?</p>
<p>First off, I&#8217;m going to assume you know what Unicode is. If you don&#8217;t then head <a title="What is Unicode?" href="http://www.unicode.org/standard/WhatIsUnicode.html">over here</a> to read a great explanation from the people that manage it. We&#8217;re going to be aiming to create a keyboard that lets us input any character from Unicode version 6. That means we&#8217;ll need to be able to easily and quickly enter a series of hexadecimal characters like U+2605 (Black Star). We&#8217;ll also want  a list of recently used characters so we don&#8217;t have to remember the codes, and maybe some kind of browse and search mechanism so we can easily find characters without having to look them up online.</p>
<p>Here&#8217;s a quick sketch of the basic UI we want to make:</p>
<div id="attachment_48" class="wp-caption alignnone" style="width: 610px"><a href="http://www.cwd.co.uk/wp-content/uploads/2011/05/uisketch-e1304352137765.jpg"><img class="size-full wp-image-48" title="Unicode Keyboard UI Sketch" src="http://www.cwd.co.uk/wp-content/uploads/2011/05/uisketch-e1304352255464.jpg" alt="" width="600" height="425" /></a><p class="wp-caption-text">A sketch of the user interface for the Unicode Keyboard</p></div>
<p>This is just a rough draft, we&#8217;ll refine it later but it gives you a general idea of what we&#8217;re aiming at. As you can see we have a text view above our keyboard that shows the currently selected Unicode symbol, a block on the left that lets you quickly select a recently used symbol, and a hex keypad on the right for selecting a new symbol. We&#8217;ve also got search, backspace and a few other buttons. The way we&#8217;ll use this keyboard is to dial in the code for the symbol we want, then hit the tick button on the right to send it to the input area that we&#8217;re currently editing. This is a bit of a variation from most normal keyboards that send their keypresses directly to the editing view.</p>
<h2>Getting Started</h2>
<p>The best place to start when developing a software keyboard would be the <a title="SoftKeyboard sample" href="http://developer.android.com/resources/samples/SoftKeyboard/index.html">SoftKeyboard</a> sample provided in the Android SDK. This implements a basic Latin QWERTY keyboard using most of the built in classes and it provides a good base if you&#8217;re creating a keyboard that is in any way &#8216;normal&#8217;. Also of use are the documentation pages for the classes in the <a title="InputMethodService namespace documentation" href="http://developer.android.com/reference/android/inputmethodservice/package-summary.html">InputMethodService </a>package. We&#8217;ll start off by cloning the SoftKeyboard sample, and then we&#8217;ll modify it to suit our purposes.</p>
<p>One word of warning before we get going. This isn&#8217;t a walkthrough, so I&#8217;m not going to detail every single thing that needs doing to make the code compile and the project work. I&#8217;ll give you the broad strokes and expect you to fill in the little details. I&#8217;ve always been a great believer in figuring stuff out for yourself, so this isn&#8217;t going to be a copy/paste style tutorial. </p>
<p>First we&#8217;re going to create a new layout that is going to house our new user interface. The standard mechanism within the sample uses the XML file <em>/res/xml/qwerty.xml</em> to define all the keys in the keyboard, the characters shown on them, the keycodes they send and the basic layout spacings. This XML file isn&#8217;t a standard layout file like we see elsewhere in Android projects, its a specialised version that the <a title="Keyboard class" href="http://developer.android.com/reference/android/inputmethodservice/Keyboard.html">Keyboard</a> and <a title="Keyboard.Key class" href="http://developer.android.com/reference/android/inputmethodservice/Keyboard.Key.html">Keyboard.Key</a> classes parse to create and setup the <a title="KeyboardView" href="http://developer.android.com/reference/android/inputmethodservice/KeyboardView.html">KeyboardView</a>. We&#8217;re going to copy the <em>qwerty.xml</em> and create our own new <em>unicode.xml</em> variation that specifies all the keys we&#8217;ll use for our hex input and our recently used character buttons.</p>
<p>The standard KeyboardView provides no way for us to add a TextView to this layout as the KeyboardView is just a specialised view class that has code to render the keys in its own drawing methods. So instead of making an entirely new KeyboardView class from scratch, we&#8217;re going to reuse the existing functionality for the normal keys within our keyboard, and wrap that view in a layout that gives us the other views we need. We&#8217;ll do this by modifying the <em>/res/layout/input.xml</em> file and wrapping the LatinKeyboardView element within a LinearLayout that will let us position our TextView that will show us what Unicode character we have currently selected. Something like this:</p>
<pre class="brush: xml; collapse: true; light: false; title: ; toolbar: true; notranslate">
&lt;LinearLayout
	xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
	android:id=&quot;@+id/wrapper&quot;
	android:layout_alignParentBottom=&quot;true&quot;
	android:layout_width=&quot;match_parent&quot;
	android:orientation=&quot;vertical&quot;
	android:layout_height=&quot;wrap_content&quot;&gt;
    &lt;RelativeLayout android:layout_height=&quot;wrap_content&quot;
    				android:layout_width=&quot;wrap_content&quot;
    				android:id=&quot;@+id/relativeLayout1&quot;
    				android:background=&quot;@drawable/charbar_back&quot;&gt;
        &lt;ImageButton android:id=&quot;@+id/btn_send&quot;
        				android:layout_width=&quot;wrap_content&quot;
        				android:layout_height=&quot;wrap_content&quot;
        				android:layout_alignParentRight=&quot;true&quot;
        				android:layout_marginLeft=&quot;3dip&quot;
        				android:background=&quot;@drawable/bar_button&quot;
        				android:layout_centerVertical=&quot;true&quot;
        				android:src=&quot;@drawable/sym_keyboard_addchar&quot;&gt;&lt;/ImageButton&gt;
        &lt;ImageButton android:id=&quot;@+id/btn_backspace&quot;
        				android:layout_width=&quot;wrap_content&quot;
        				android:layout_height=&quot;wrap_content&quot;
        				android:layout_toLeftOf=&quot;@id/btn_send&quot;
        				android:layout_marginLeft=&quot;3dip&quot;
        				android:src=&quot;@drawable/sym_keyboard_delete&quot;
        				android:layout_centerVertical=&quot;true&quot;
        				android:background=&quot;@drawable/bar_button&quot;&gt;&lt;/ImageButton&gt;
        &lt;TextView style=&quot;@style/hexBar&quot; android:layout_width=&quot;wrap_content&quot;
        				android:layout_height=&quot;wrap_content&quot;
        				android:id=&quot;@+id/preview&quot;
        				android:layout_toLeftOf=&quot;@id/btn_backspace&quot;
        				android:layout_alignParentLeft=&quot;true&quot;
        				android:layout_centerVertical=&quot;true&quot;
        				android:hint=&quot;@string/charbar_hint&quot;
        				android:background=&quot;@drawable/charbar_textfield&quot;
        				android:textColor=&quot;@color/charbar_text&quot;
        				android:cursorVisible=&quot;false&quot;&gt;&lt;/TextView&gt;
    &lt;/RelativeLayout&gt;
	&lt;com.example.android.softkeyboard.LatinKeyboardView
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        android:id=&quot;@+id/keyboard&quot;
        android:layout_alignParentBottom=&quot;true&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        /&gt;
&lt;/LinearLayout&gt;
</pre>
<p>If you compare this to the original <em>/res/layout/input.xml</em> file you will see that we&#8217;ve kept the original LatinKeyboardView element, but we&#8217;ve wrapped it in a LinearLayout, and added a RelativeLayout above it that contains our text view and some buttons for sending the character and deleting mistakes.</p>
<p>In order for the new view to show and not cause a nasty crash we&#8217;re going to have to modify the <em>SoftKeyboard.onCreateInputView</em> method so that it returns the LinearLayout rather than just the LatinKeyboardView as it does right now:</p>
<pre class="brush: java; collapse: true; light: false; title: ; toolbar: true; notranslate">
    @Override public View onCreateInputView() {
    	LinearLayout layout = (LinearLayout)getLayoutInflater().inflate(
                R.layout.input, null);
    	mLayoutView = layout;
        mInputView = (KeyboardView)layout.findViewById(R.id.keyboard);
        mInputView.setKeyboard(mUnicodeKeyboard);
        return mLayoutView;
    }
</pre>
<p>Finally, in order to get the new keyboard to show we need to add some new lines to our <em>SoftKeyboard.onInitializeInterface</em> method to create the new keyboard from the <em>unicode.xml</em> file:</p>
<pre class="brush: java; highlight: [2]; title: ; notranslate">
        mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
        mUnicodeKeyboard = new UniKeyboard(this, R.xml.unicode);
        mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
        mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
</pre>
<p>We have to add our new UniKeyboard class which is just an extension of the LatinKeyboard that came with the sample. It doesn&#8217;t do anything right now but it will come in useful later on:</p>
<pre class="brush: java; collapse: true; light: false; title: ; toolbar: true; notranslate">
package com.example.android.softkeyboard;

import java.util.ArrayList;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.inputmethodservice.Keyboard.Key;
import android.inputmethodservice.Keyboard.Row;

public class UniKeyboard extends LatinKeyboard {
    public UniKeyboard(Context context, int xmlLayoutResId) {
        super(context, xmlLayoutResId);
    }

    public UniKeyboard(Context context, int layoutTemplateResId,
            CharSequence characters, int columns, int horizontalPadding) {
        super(context, layoutTemplateResId, characters, columns, horizontalPadding);
    }
}
</pre>
<p>We&#8217;ll also need to decide when to show our keyboard, for now we&#8217;re just going to always show it so that we can get this part of it working during our testing. So at the end of our <em>SoftKeyboard.onStartInput</em> method we&#8217;ll insert the following line:</p>
<pre class="brush: java; highlight: [1]; title: ; notranslate">
        mCurKeyboard = mUnicodeKeyboard;
        // Update the label on the enter key, depending on what the application
        // says it will do.
        mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
    }
</pre>
<p>That should be enough hints to get you to a point where you can load your own custom keyboard layout, and add some additional views as furniture around it. In my next post I&#8217;ll detail how we make the keycodes from our new keyboard buttons go to the right place, and how we eventually send the character to the input view that is being edited by the IME.</p>
<p>Look for the next posts in the coming days, while the project may only take us the next 3 days to implement it appears that writing blog posts could take considerably longer!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/04/29/the-making-of-unicode-keyboard-1/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Hot Beverage (or the start of the Unicode Keyboard)</title>
		<link>http://www.cwd.co.uk/2011/04/29/hot-beverage-or-the-start-of-the-unicode-keyboard/</link>
		<comments>http://www.cwd.co.uk/2011/04/29/hot-beverage-or-the-start-of-the-unicode-keyboard/#comments</comments>
		<pubDate>Fri, 29 Apr 2011 09:43:04 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[unicode keyboard]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/?p=17</guid>
		<description><![CDATA[Some people got married this weekend and this means we have a nice long bank holiday. Sadly my other half is stuck having to finish lots of coursework at the moment (see her progress over at sew.ciety when she has time to update it). This means we&#8217;re stuck inside and can&#8217;t go off to enjoy ...]]></description>
			<content:encoded><![CDATA[<div class="mceTemp"><a title="Royal Wedding in Lego" href="http://blog.craftzine.com/archive/2011/04/royal_wedding_in_lego.html"></p>
<div id="attachment_50" class="wp-caption alignleft" style="width: 310px"><a href="http://blog.craftzine.com/archive/2011/04/royal_wedding_in_lego.html"><img class="size-medium wp-image-50" title="Royal Wedding in Lego" src="http://www.cwd.co.uk/wp-content/uploads/2011/04/Royal-Wedding-2-300x180.png" alt="" width="300" height="180" /></a><p class="wp-caption-text">Will and Kate looking pixellated</p></div>
<p>Some people got married</a> this weekend and this means we have a nice long bank holiday. Sadly my other half is stuck having to finish lots of coursework at the moment (see her progress over at <a title="Sewing in the 21st Century...for the 19th Century" href="http://sew.ciety.net/">sew.ciety</a> when she has time to update it). This means we&#8217;re stuck inside and can&#8217;t go off to enjoy the weekend with all the other revellers. So in honour of the new CWD website we decided we&#8217;d spend the weekend creating a Unicode Keyboard for Android.</div>
<p>&nbsp;</p>
<p>Our chief tester has a pet love for the Unicode Character &#8216;HOT BEVERAGE&#8217; (U+2615)&#8230;</p>
<p><span style="font-size: 600%;">☕</span></p>
<p>(If that appears as a square block to you then you&#8217;re probably using Chrome or Safari, these browsers apparently don&#8217;t do fallback fonts properly right now, try looking at it in FireFox)</p>
<p>But he&#8217;s found it really hard to express his ♥ for his hot beverage of choice on his Android phone. So we decided we&#8217;d solve this issue for him this weekend.</p>
<p>The next few posts will document how we did this and should culminate in the release of the Unicode Keyboard app for you to try out yourself at the end of the bank holiday.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/04/29/hot-beverage-or-the-start-of-the-unicode-keyboard/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Progress update</title>
		<link>http://www.cwd.co.uk/2011/03/28/progress-update/</link>
		<comments>http://www.cwd.co.uk/2011/03/28/progress-update/#comments</comments>
		<pubDate>Mon, 28 Mar 2011 11:14:00 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[pinman]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[update]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/2011/03/28/progress-update/</guid>
		<description><![CDATA[Been a little while since my last post about my little Android game PinMan, thought it was about time to do an update on how things are going. I&#8217;ve released two new updates since my last post, both fairly minor bug fixes, though I also added capability for users to create their own outfits and ...]]></description>
			<content:encoded><![CDATA[<p>Been a little while since my last post about my little Android game PinMan, thought it was about time to do an update on how things are going.</p>
<p>I&#8217;ve released two new updates since my last post, both fairly minor bug fixes, though I also added capability for users to create their own outfits and backgrounds in the paid version of the app. This saw a significant uptick in the number of sales of the paid version, from barely one sale per day to somewhere in the region of 3-5 sales per day. Definitely a lesson to be learnt here &#8211; if you&#8217;re going to have a free version of your app, ensure there&#8217;s significant value in the paid version to justify the upsell.</p>
<p>I&#8217;ve also been experimenting with launch days and timings. Since the app has very little marketing and hasn&#8217;t managed to get &#8216;featured&#8217; the visibility boost it gets from a new update is quite significant. However the competition for space in the &#8216;Just In&#8217; lists on the Android Market is fierce, with somewhere in the region of 20-30 apps appearing there every day. So I&#8217;ve been experimenting with which day is best to launch on, initially trying out a Thursday afternoon launch, a Saturday release, and a Sunday release. They all work fairly well to be honest, but I think Sunday has a slight edge given that the number of apps added to the Just In list is fewer on a Sunday so your app remains visible for longer.</p>
<p>So, some stats&#8230;as of the time of writing the free version of the app has been installed just over 28,000 times. I feel thats quite good considering the lack of significant marketing effort and the fact its only been out for a month. Its now also had just over 100 purchases of the paid version. Total earnings therefore are still pretty low, more beer money levels than rent money levels, but every little helps.</p>
<p>Whats next? Well, there&#8217;s certainly more updates to be done on PinMan, and there have been many requests for additional features from users. I also have a couple of other games in mind which I would hope would do better than PinMan by virtue of being more of a traditional game style than the very casual style used in PinMan. I think I shall also spend some time improving my graphic design skills, as I can already see significant improvements in my design work, which will help me in so many areas its worth spending the extra time on.</p>
<p>April is going to be a busy and exciting month I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/03/28/progress-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PinMan &#8211; A casual game for Android</title>
		<link>http://www.cwd.co.uk/2011/03/12/pinman-a-casual-game-for-android/</link>
		<comments>http://www.cwd.co.uk/2011/03/12/pinman-a-casual-game-for-android/#comments</comments>
		<pubDate>Sat, 12 Mar 2011 15:59:00 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[pinman]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[physics]]></category>

		<guid isPermaLink="false">http://www.cwd.co.uk/2011/03/12/pinman-a-casual-game-for-android/</guid>
		<description><![CDATA[Its been a while since my last update. But I haven&#8217;t abandoned this blog yet. I&#8217;ve just been really busy working on lots of things at once. The CircuitBee project is coming along nicely (major rethink going on right now&#8230;but thats a story for another post), but is still taking an inordinately long time to ...]]></description>
			<content:encoded><![CDATA[<p>Its been a while since my last update. But I haven&#8217;t abandoned this blog yet. I&#8217;ve just been really busy working on lots of things at once.</p>
<p>The <a title="CircuitBee - Electronic schematics in your browser" href="http://circuitbee.com">CircuitBee </a>project is coming along nicely (major rethink going on right now&#8230;but thats a story for another post), but is still taking an inordinately long time to come to fruition. This gets really depressing after a while, so I&#8217;ve found that its great to take a break from my &#8216;big project&#8217; to work on something smaller and short term to gain a bit of confidence and relieve the monotony a little.</p>
<p>So at the end of February I started work on what was supposed to be a small Android game. I quickly realised however that the work involved in making a whole game was rather large, so I&#8217;d need to break it down into steps that could be managed in a reasonable timeframe.</p>
<p>The original idea for the game was (and still is) called FallingMan, and involves a ragdoll man falling from the sky banging into things. This seemed like a simple project at first, but I soon discovered it was like every other software project out there &#8211; far more complicated than it first seemed. So as a halfway step to implementing the full game, I decided to create PinMan.</p>
<p>PinMan is a ragdoll stickfigure who you can shake around, throw at the wall, toss objects at and even pin to the wall with drawing pins (hence his name). This was a great little project to start off with, and it has given me most of the technology I need to create the FallingMan game.</p>
<p>We released PinMan on th 25th February, and saw about 3000 installs on the first weekend (Friday to Monday). This is for the free version of course, as the paid version picked up a very low number of installs. After the launch weekend the rate of installs fell back to a reasonable 300 new users per day. The free ad supported version has since ticked along at a slightly increasing rate of new installs, and is earning a few bucks a day through the advertisements. Not going to pay the bills or make me rich, but still, not bad for a halfway step to creating something else.</p>
<p>Since then I&#8217;ve made a couple more releases of the app, with some improved features for the <a title="PinMan on the Android Market" href="https://market.android.com/details?id=uk.co.cwd.pinman" target="_blank">paid</a> and <a title="PinMan Free Edition on the Android Market" href="https://market.android.com/details?id=uk.co.cwd.pinman.free" target="_blank">free</a> versions, and put together a <a title="PinMan" href="http://cwd.co.uk/pinman" target="_blank">small website</a> to showcase the app and a video of it in action. We now have almost 15,000 installs of the free version and are nearing 50 installs of the paid one. I&#8217;m quite pleased with this result for a couple of weeks work!</p>
<p>I&#8217;ve attached the video I made of the app below, making the video itself was an interesting experience which maybe I will recount some other day. I hope you enjoy it!</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cwd.co.uk/2011/03/12/pinman-a-casual-game-for-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

