Monday, May 31, 2010

Basic graphics with Android

I have been working on a small game, and come across a real lack of useful information on how to develop a non-real time game. (i.e. A game that is entirely event driven.)

I started with the usual route, attempting to use existing UI objects to create the look that I wanted. However, I was unable to get the look and behavior that I wanted. So, I looked closer at the Lunar Lander sample in the Android SDK. The problem is that the Lunar Lander sample was perfect if you wanted to develop a real-time game. But, I didn't.

So, what to do? After much Googling, I found suggestions that what I really wanted to do was create a specialized view that would contain my game board. Doing this turned out to be easier than I thought it would. Using the Eclipse wizards, I created a new class that would be my game board view. The class was derived from the View class. The simplistic class would look something like this :


package com.example.simplegame;

public class BoardView extends View {
public BoardView(Context context) {
super(context);

}

public BoardView(Context context, AttributeSet attrib)
{
super(context, attrib);

}
}


Now, let me save you some time and pain. When I started this effort, I used "super(context)" inside the second constructor. Doing that will prevent you from using findViewById() to get a pointer to the view in your form.

Okay, so now we have a basic class set up. But, it doesn't actually do anything useful. What we really wanted to do is have a small blue box drawn on our view. So how do we do that?

Simple. We add an onDraw() method to our class. onDraw() takes a single parameter, with is of type Canvas. The canvas is what we will draw on, and what will ultimately be shown on the screen. As previously stated, we want to draw a simple blue square on the screen, so our onDraw method should look something like this :


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint p = new Paint();
p.setAntiAlias(true);
p.setARGB(255, 0, 0, 255);

canvas.drawRect(0, 0, 10, 10, p);
}


Before we move on to talk about how to use our new View in a form, I want to point out a little bit more information on how onDraw() works. According to the Android documentation, you should assume that the canvas passed in to onDraw() is blank. (That is, you should never rely on anything you have previously drawn to still exist on the canvas.) Because of this, you will need to redraw your entire view each time onDraw() is called. In our sample, we draw the blue square each time onDraw() is called.

Now that we have a new view class set up, we need to figure out how to put it in a form, and use it. To make things easy, I first created a simple form with a generic View that fills the entire screen. It looks something like this :


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<View android:id="@+id/View01" android:layout_width="fill_parent" android:layout_height="fill_parent"></View>
</LinearLayout>


Now that we have our layout, we need to modify it to include our custom view. To do this, we change the <View> tags to be <com.example.simplegame.BoardView>. If you then take this class, and this form and wrap it in some boiler plate code that would display the form, you will get a form with a small blue square in the top left corner of the screen.

If you do some experimenting, you will find that you get the blue square on the screen even if you don't establish a pointer to the BoardView object in the form. While it may seem strange at first, if you think about it you will realize that all of the objects on a form exist as soon as the form is inflated. The findViewById() call is simply giving you a pointer to the object that already exists in memory. Therefore, the onDraw() method is called, even if your main program doesn't have a pointer to the view.

Wednesday, May 19, 2010

Meru configuration, part 1

As promised, I am going to give the QuickPhones phone a shot with the Meru gear. But first, I need to get the gear set up.

A quick rundown of what my configuration will look like :
1 - Meru MC 500 controller running version 3.4-103 software
1 - Meru MN-AP320
1 - Meru MN-AP201RH

I powered up the unit, and plugged in to it via a USB->Serial dongle. As the instructions indicated, I set up the serial port to 115200,8,N,1. I watched as the controller booted some flavor of Linux, and then hung on the "Starting Meru 3.4-103 wireless LAN services ...". After sitting for a while, I figured something was wrong, so I power cycled the box to see if it would come up a little quicker. (It didn't.)

I figured there was something wrong with my unit, so I pulled up a text editor to start writing my blog entry about how much I would have loved to write the entry about the QuickPhones with Meru. While I was getting everything together, the console spit out an error message, and then prompted me for a login.

I went ahead and put the default admin/admin username and password and got the console prompt back. At the console prompt, I ran the "setup" process. After answering the normal questions (ip address, gateway, netmask, etc.) the unit asked if it could reboot. (So I let it. Shocking, huh?)

Fortunately, it rebooted a lot faster than the initial boot. After a minute, I was able to log in and was back at the command prompt.

Normally, I am the kind of person that hates to configure gear with the web interface. But, in this case I decided to make an exception since the goal is not to evaluate the Meru gear, but rather to see if the phone works better on it. I fired up Firefox, and hit the web page. At this point, I was informed that I needed to use Internet Expoliter to access the UI on the box. (As an aside, I am sure that the version of code I am using is older. But, I still have to say, REALLY!? *sigh*)

Since I am already inflicting punishment on myself, I figured I would give IE 8 x64 a shot. When I hit the web site, I was first told that the certificate on the unit was suspicious (which is normal on gear like this), and after telling IE it was okay to continue, I was prompted for the username and password.

The UI that was displayed is reasonably clean, but doesn't show any useful information initially. (Probably because I don't have any APs it can talk to.) So, I pulled out the AP201RH. The first thing I noticed is that the AP appeared to want power over ethernet (PoE). So, I tried plugging it in to port 2 on the controller in hopes that it would power on. But, it seems that either port 2 doesn't do PoE, or there is some configuration setting that I need to enable before it will do it. Again, since I really want to get to the QuickPhones testing, I just took the AP in to another room that had a PoE port that I knew would work.

I managed to get the AP201RH up and running easily enough. So I plugged in the AP-320 so I could get it configured and ready to rock. Unfortunately, the AP-320 is running a different version of code, and try as I might, I am unable to upgrade, or downgrade it. Since the controller sees the AP as an AP-100, I am guessing this is a good thing.

Unfortunately, this is a dead end for this effort. I'll have to see if I can track down my friend at Meru to see if I can get some help. (The gear I have is test gear, so I don't have a maintenance contract to get the latest versions of code.)

I hope to have more in the coming weeks, assuming I can reconnect with an old friend.

Monday, May 17, 2010

Stupid Android ListView tricks

I recently made some major changes to the Movie Track app that I put out. What started as an app that I did for my own use seems to have gained a few users. So, I decided to upgrade the look and feel a bit. In the process of this, I changed several of the screens from using a ListActivity to using a normal XML layout that contained a ListView. After mucking around with all of the settings to get things looking the way I wanted, I ran in to an interesting snag.

Everything displayed the way I wanted it to, but to "click" on an item that was in the ListView, you had to actually "click" on the text of the ListView, and not just on the row in the ListView. Perhaps I am a perfectionist at some level, but this annoyed me to no end.

Much Google later, I couldn't find the answer on how to do it. So, I started to mess with settings. A hair-brained idea or two later, I decided to try changing the ListView's layout-width from "wrap_content" to "fill_parent". Amazingly enough, that did exactly what I wanted!

Sure, this was a bit of a "duh" experience, and a newbie mistake. But, I figured I would publish it here in case some other developer runs across the same thing, and gets as frustrated as I was getting!

Sunday, May 16, 2010

Adding the Mob to Android (Part 2)

So, if you followed my previous AdMob post, you should have your app listed in AdMob, have the SDK downloaded, and have the documentation available. If you don't, you should go look at previous articles in my blog to find the steps followed to get all of these things.

Since I rebuilt my development machine recently, the first step I took was to make sure the code for my app would still run in the emulator. This proved two things to me. 1) My development environment is solid and configured correctly. 2) My program is still working as I would expect it to. I did this because it is always a good idea to know that what you have works before you go sticking new and unknown stuff in to your app.

When I first loaded my project in to Eclipse, I got the error, "Android requires .class compatibility set to 5.0. Please fix project properties." As I recall, there were some requirements on the JDK that is used with Android, so I assume that this error message is a direct indication of what needs to be done to make sure my code still works. But, this error message is also not entirely clear. Have no fear, wizards are here! Right click on your project in Eclipse, then select "Android Tools > Fix Project Properties", and all of our problems are solved!

Now, it is time to get to the meat of the work. For the sake of brevity, I won't recreate all of the information contained in the SDK document you should have already downloaded. Instead, I will reference that document, and provide my own commentary on anything that I feel wasn't explained very well.

If we turn our SDK documents to page 2 (or, the first page following the title page), we see the first few steps to getting AdMob installed. My project didn't have the lib directory, so I went ahead and created it. Following the instructions in step 1 is pretty straightforward. However, I did run in to one thing that wasn't covered. When you create the lib directory, and copy the jar over you need to refresh your project, or else you won't be able to find the jar file you need to add. If you click on your project in Eclipse's package explorer, and hit the F5 key, you will see the lib directory added to your project. Now you should be able to follow the rest of the instructions in step 1.

For the most part, the rest of the instructions make sense. However, the final instruction that indicates how to get a test ad appears to have changed a little. The instructions indicate that you should look in the logcat output for a string that identifies your test device. It may be that this is what you need to do when debugging on an actual device, however, if you are just working in the emulator you only need to add the line "AdManager.setTestDevices(new String[] { AdManager.TEST_EMULATOR } );" to your onCreate() method.

If you followed all of the instructions carefully, you should now have an ad enabled version of your program! Now go make some money!

Saturday, May 15, 2010

Using Ubuntu 10.04 LTS server for Subversion

My old subversion server is in need of a bit of an upgrade. I decided to move it to one of my VMware ESXi servers. (Yes, I really have ESXi servers in my basement. What can I say?) Anyway, since this is a low volume service, moving to an ESXi server seems to be the most economical way to keep my code safe without running the power bill (any farther) through the roof.

Since I have enough VMs to keep track of, I am going to build this one on Ubuntu 10.04 LTS, since Ubuntu seems easier to keep up-to-date. However, taking you step-by-step through the installation isn't something I am going to do. Rather, I will comment on any "non-standard" steps I take, and then include all of the follow-up information needed to get the subversion server up and running.

When I installed the server, I didn't select any of the options on the type of server I wanted to set up. Instead, I just continued past that screen and completed the installation. Once the machine rebooted, I logged in with the account I created, and got to work.

The first two things you will probably want to do is set a static IP address for your server, and install the openssh server so you can work on the machine remotely. Setting the static IP is easy. Good instructions can be found here : http://www.howtogeek.com/howto/ubuntu/change-ubuntu-server-from-dhcp-to-a-static-ip-address/. Installing OpenSSH is also easy. At the server's command line run the command "sudo apt-get install openssh-server".

Once the IP address is set, you will either need to reboot the machine, or manually change the address by hand. I suggest a quick reboot, as it shouldn't take too long. Once the machine reboots, we can get on to setting up and configuring the subversion server.

There are several different ways to configure a subversion server. And I have used many of them. By far, my preferred method is to do subversion over http as the Tortoise SVN client for Windows will let me cache my username and password in this mode, and not have to enter it a bunch of times anytime I do any work in the repository.

So, the first thing we need to do is install Apache. I went ahead and installed it using the command "sudo apt-get install apache2". After a few seconds, I had Apache installed and ready to rock.

The next thing I needed to do was actually install subversion. This is easily done by running the command "sudo apt-get install subversion". After a few more seconds, I had subversion installed.

If we Google around, we can find some information on what to do next at https://help.ubuntu.com/community/Subversion. The only problem is, that I am using the server version, so the UI steps are of little help. But no problem, we can easily do the same thing from the command line!

First, we want to create a subversion group to use. To do that, we need to run the command "sudo addgroup subversion". You should get a message indicating that the group was added, along with listing the GID (group ID) of the group that was just created.

To do that, run the command "sudo nano /etc/group", then find the group we just created, and add both "www-data" and your username to the end of the subversion group line.

Now, you should be a member of the subversion group, but you will need to log out and back in before the change will take affect. So do that now.

Next, we need to create the directories to store the files that we upload via subversion. To do that, execute the following commands :

cd /home
sudo mkdir svn
cd svn
sudo mkdir repo
sudo svnadmin create /home/svn/repo


Then, fix the permissions with these commands :

cd /home/svn
sudo chown -R www-data:subversion repo
sudo chmod -R g+rws repo

Now, to bring things full circle, we need to make sure we have the Apache 2 SVN libraries installed. To do that, run the command "sudo apt-get install libapache2-svn".

Now, we need to edit the Apache config so that it knows how to deal with the subversion requests. Change in to the directory /etc/apache2/mods-available, and run the command "sudo nano dav_svn.conf". Then, add the following block to the end of the file to enable subversion through Apache :


DAV svn
SVNPath /home/svn/repo
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/subversion/passwd

Require valid-user




Whew! This is a lot of work. BUT, we are almost there! The last thing we need to do is set up authentication for the web interface so that not just anyone can muck around in our repository. Doing that is easy. Run the command "sudo htpasswd -c /etc/subversion/passwd " where is replaced with the user name you want to use to log in. To add additional users, use the same command line, but remove the "-c" option. (If you don't remove the -c option you will erase the first user you created!!!)

Congratulations! At this point, you should have a subversion server all set up! To access the server, you would use the URL http://
/svn .

What does it take to add the Mob to your existing Android applications?

When I get bored, I code. And when I get money hungry, I also code. I currently have one app out on the Android marketplace, that has been downloaded several times. In all honesty, I didn't expect the app to become the next big thing. I also wasn't sure it would be useful to people beyond myself. But, it seems that there are at least a few other people out there that believe my Movie Track app has some value.

Now, to be fair, I am all for free apps. I have done a lot of free open source development in my time, and have generally enjoyed it. But, I also like to get a little something extra out of my work when possible. So, I have decided I am going to try adding AdMob to my Movie Track program, and see if I can generate a few bucks along the way. (For those that hate ads, I'll also offer an ad-free version for $1.)

Signing up for AdMob is pretty easy. Just hop over to the AdMob web site, and create a new account. Once the account is created, you will get an e-mail with a link that needs to be clicked in order to verify the e-mail account is yours. But, once you have done that, it starts to get confusing in a hurry as to what to do next.

First, some terminology. When I first logged in with my shiny new account, there was a lot of talk about "Advertisers" and "Publishers". Since we are putting ads in to our programs, we are "Publishers". So, unless you want to advertise things in other people's programs, you should look for information that pertains to publishers.

Once you log in to the site, and click on the Marketplace link, the Campaigns tab shows information that is only relevant to advertisers. Or does it? Clicking on the "New Advertiser Training Videos" takes you to a page with videos about how to use AdMob to advertise new products and services. However, if you scroll down toward the bottom of the page, you will also find that there are videos for publishers down there as well.

A quick look at some of those links tell us that we need to create an Android App profile on the AdMob site in order to allow us to put ads in, and track the results. To do this, we need to hover over the "Sites & Apps" tab, and select the "Add Site/App" option from the drop-down menu. Next, click on the "Android App" icon, and scroll down to enter the rest of the information.

As you fill this form out, there is a section for the Android package URL. The help information that is available says it must be a mobile site, or the URL to your package in the market place. (The FAQ says the URL in the market place will be formatted as : market://details?id) However, digging around, it seems there should be a "=" between the "id" and the "". You can find more information at http://developer.android.com/guide/publishing/publishing.html.

This left me with a couple of questions that I will probably post more about later as I dig deeper. The first one is, "What is this URL used for?". And the second is, "What if I have not yet published the app? What do I put in there?".

Since this field isn't in bold, I am going to guess that it may not be important what goes in there. But, I like to be complete where possible, so I will be putting in the link to my app in the form of "market://details?id=info.geektaco.movietrack". For the category, I selected "Entertainment", and then I entered a description of the Movie Track program, and clicked the "Continue" button.

It would appear that I entered the correct information, as the next screen I was presented with is a link to download the "Install Code" to add to my program. I went ahead and grabbed the SDK, and a copy of the PDF version of the SDK documentation for later use, and then clicked "Go to Sites/Apps".

Now, we are getting somewhere. We should now see the dashboard for AdMob. In the dashboard is a link to update your payment information. That part seems pretty straight forward, so I won't go in to detail here.

And now, for the fun part! Let's add the ads to our program, and go make some money!!!

(Continued in later posts)

Friday, May 14, 2010

The final(?) word on the QuickPhones phone.

It has been a while, but a few weeks ago I go another update from the QuickPhones guys about the multiple AP issue that I ran in to. I was extremely disappointed to hear that they were unable to find a fix for the multiple AP issue, and have given up trying.

So, what can I say? I will still tell you that this phone has the best battery life of any of the lower priced wifi phones out there. (I have not had a chance to try the more expensive ones. Feel free to contact me if you want to send me one!) When I didn't have it associated to a network, and just sitting on my desk the battery lasted about a month. When connected to an AP, the battery lasted about a week.

Now, just to be clear, it is possible that this phone would work perfectly on wireless gear that "pretends" to be a single huge AP. The one that comes to mind is Meru networks. I have some Meru gear that I am going to install, and will post a follow-up on this phone once I get it installed.

I have, however, discovered a bit of a workaround to the multi-AP issue. If you happen to have a single AP around that can broadcast another SSID, you can still use the phone in an area with multiple APs on one SSID. To do this, you need to shut down all of the APs that are broadcasting the same SSID so that the phone can pick up the AP that is single.

That didn't make a lot of sense, so let me expand on it. Lets say you have 5 "brand X" APs, all broadcasting an SSID called "CorporateFoo". While those APs are all broadcasting the SSID, the phone will be unable to consistently see any SSIDs around you. So, to get the phone working, you need to run to your local electronics store and purchase an inexpensive "brand Y" AP. Set that AP up and name it something like "IWishQuickPhonesWorkedOnMultiAPNets". (yes, I know that is too long for an SSID.. work with me here.) Now, shut down all of the APs that are broadcasting the "CorporateFoo" SSID, and reboot your QuickPhone. When the phone comes back up, it should be able to see your single AP that is broadcasting the "IWishQuickPhonesWorkedOnMultiAPNets" SSID. Configure the phone to use this SSID, make sure it connects and can talk to your SIP server. Once you verify it is working, you can turn your other APs back on. Now that you have the configuration set in the phone, it should always talk to the single AP. When it is powered on, it might take a while to find the AP, but it should eventually connect to it.

So, in a nutshell, if battery life is king for you, and you either only have a single AP, or don't mind jumping through hoops to get your phone working, the QuickPhone is what you want. If having a phone off the charger and on standby for more than 24 hours isn't important, then I recommend the UniData phone I reviewed a few months ago. It is a solid phone that has been working perfectly in my environment.

Monday, May 3, 2010

Xfce and Ubuntu

The title may be a bit misleading. It is likely that this is really an Xfce issue only.

When I upgraded my Revo from Gentoo to Mythbuntu I ended up with a situation where the font size was significantly larger than it should have been. Okay, perhaps "significantly larger" would be an understatement. The clock on the menu bar was so large, I could only see the bottom lines for the numbers!

Googling around found that the issue was with Xfce trying to determine the best font size by using the DPI values from X. X, in turn, got the DPI information out of the EDID information from the monitor. I am sure in most cases this works just fine, but when you bring a cheap LCD flat panel TV in to the equation along with an ION graphics card, the results are less than stellar.

After searching many web pages looking for the answer, I finally found it in the first place I SHOULD have looked. (Yeah, I can admit when I was being stupid.) If you hop over to the MythTV Wiki at http://www.mythtv.org/wiki/Specifying_DPI_for_NVIDIA_Cards you can find the "magical" answer to the problem.

Specifically, you need to add the following options to the "Monitor" section :

Option "UseEdidDpi" "FALSE"
Option "DPI" "100 x 100"


After this, everything started to look reasonable on my screen again!

Sunday, May 2, 2010

Of Acer Aspire Revo and Ubuntu 10.04 LTS

I have been running one of my Myth frontends on an Acer Aspire Revo for a while now. When I first got it, I loaded it up with Gentoo, which was my favorite distro at the time. Since then, I have set up several other frontends using Mythbuntu, all of which speak to my backend still running on Gentoo.

Since all of my frontends except one were running Mythbuntu, I decided to do myself a favor, and convert the last one to Mythbuntu as I upgraded toward the final 0.23 release of Myth. It seemed like it would be a pretty straight forward thing to do, but it turns out, it isn't so straight forward.

I managed to get the system to install reasonably pain free. I selected my usual options during install, such as using the proprietary NVidia drivers, instead of the open source ones. (Mainly because I need VDPAU, or else these low power machines won't be able to keep up.) Following the final reboot, I saw some text on the screen about a failure to load something related to the NForce chipset, quickly followed by a blank screen. But, not just any blank screen, the blank screen my TV gives when there is either no signal, or an invalid signal on the input.

Needless to say, this was annoying. After running some nmap to chase down the DHCP address given to this machine, I was able to log in. While looking through a "ps xaf" output, I noticed that there was a process called "zenity" running, that seemed to be trying to display an error message about Ubuntu running in low graphics mode. Googling around found that this usually happens when the driver installed is incorrect, or improperly configured.

A quick "lsmod" showed that the expected nvidia kernel module wasn't running! At this point, it seemed pretty clear why the configuration didn't work! Looking through the available apt packages, I couldn't locate the proprietary nvidia drivers. (Or, at least they weren't where I expected them to be.)

A bit more Googling around came across this web site : http://www.ubuntugeek.com/howto-install-nvidia-drivers-manually-on-ubuntu-10-04-lucid-lynx.html

So, what does it all mean? Darn good question. I am far from an expert on the subject, but it would seem that the latest version of Ubuntu doesn't have a way to install the NVidia driver without going through the old method of downloading it directly from NVidia, and doing the work yourself.

What I can say, however, is once I followed the instructions from the link above, my machine booted right up in to X, and started working as I would have expected.