Showing posts with label development. Show all posts
Showing posts with label development. Show all posts

Monday, May 27, 2013

Why all the Google Glass hate?

I suspect I am opening a can of worms here, and will probably end up getting flamed wildly in the comments telling me that I am stupid or whatever else.   However, I can't help but notice that most of the complaints about Google Glass are either based on a completely flawed understanding of what Glass is, and can do, or fears of a surveillance society that already exists in much worse ways.

Let me start by saying, I have Google Glass.   But, I also take my privacy really seriously.  I don't have a Facebook account and have requested that anyone I know not post pictures of my family to Facebook or any other social networking sites without my approval.   I do have a twitter account, but I don't ever use it.  I got it so that I could develop some software for a friend that he wanted to use with twitter.   I also take the time to go to as many sites like Spokeo as possible and ask them to remove my information.  When a store asks me for anything but the money to pay for my purchase my response is "Why?".  Finally I am the bane of TSA's existence because I believe that if some stranger playing police officer hasn't touched my junk, the flight will almost certainly have some horrible ending.  So, I always opt out.   While I am sure there is more I can do to protect my privacy, hopefully you will understand that I take my privacy very seriously.

When Google Glass was originally announced I had some concerns about privacy myself.   However, because of the industry I am in, I need to stay on top of the latest technology when it incorporates wireless networks.  What I have found in Glass is far less concerning than what I had imagined in my mind.  (You'll have to trust me.  The technology in your mind is far superior to what currently exists!)  So, I would like to address some of the paranoid fantasies that people have about Glass.


I don't want to have a conversation with someone wearing Glass.  They could be checking Facebook, or Twitter, or something else and not paying attention to me.

Let me start with the obvious.   It doesn't matter if you have Glass or not.  If someone would rather be checking Facebook or Twitter while talking to you, you are either boring to talk to or that person isn't worth talking to.

However, this is really a non-issue with Glass for several reasons.  First, contrary to what people seem to think, Glass does not provide a heads up display (HUD).   Rather, when properly worn the screen is just above your line of sight.  To see the screen, you have to look up.  If you are really engaged in a conversation with someone, you will notice if they start looking up.   But, lets assume for a second that you don't manage to notice that someone is looking up.  The second reason it is a non-issue is that the Glass cube above your eye will light up when it is turned on.  The amount it lights up allows for someone standing close enough to you to have a conversation will clearly see that you have something up on the screen.  In fact, it is light enough that when my sister used my Glass, I was able to see enough of the screen while looking at her to tell her how to navigate!

But, lets go crazy and assume that you have some kind of weird spot blindness that prevents you from seeing the screen and noticing it is on.   There are currently two ways to interact with Glass.  You can reach up to the side of your head and use the touch pad on the frame, or you can nod your head to wake it up and then speak to it.  Again, you will notice if someone is using Glass while talking to them.  If you don't, then you should question why you are talking to that person as you aren't engaged with them enough to notice.

But, since Glass is always recording and streaming data to Google, people will always be able to see what I am doing!

Let me ask you this.   Can your cell phone record an entire day of video?  No?  Then, consider that the battery in your cell phone is larger than the entire volume of Glass, even if you include the frames which have not electronics in them!   But maybe Glass is using some super secret system that uses less power than a cell phone which allows you to record all day!   The specs for Glass are openly available.  The hardware in Glass is basically the same as an under-clocked Galaxy Nexus.   Don't know about you, but the battery on my Galaxy Nexus lasts about a day when I use it lightly.   During heavy usage, like when I was at Google I/O, I am lucky to get half a day.  In addition, I tried recording video constantly while at I/O just to see how long it would last.  At about 55 minutes, Glass powered down.  (I had taken one or two pictures prior to recording, so I would put the actual recording time around 1 hour total on a fully charged battery.)

The fact is that Glass doesn't have the hardware that would be needed to record video all day.  And when you consider the weight issues with a pair of glasses, it is unlikely that such a device will exist in the near term.  Sure, you could wear a backpack full of batteries that connect to the micro USB port on Glass and probably get more recording done, but would you?  In reality, if someone really wants to record constantly, they will use a device that doesn't do anything but record.  Why waste battery power on processing other stuff when all you want to do is record video?

Okay, but when Glass is used to take a picture, the picture is uploaded to Google where they can tag my face and determine where I am.

This argument just floors me.  My response to it is, "And so does every other device that you have that can take a picture!"  But, you argue "Not my camera that isn't Internet connected!"  That is true for the automatically uploaded portion.  But, lets face it.  Most pictures will eventually find their way on line.  Plus, even with all of the steps I take trying to keep myself from being tagged in pictures, doing a Google Image Search on my name turns up at least one picture that is of me.  (Granted, it is over a decade old, but that is really beside the point.)   Your friends will tag you in the pictures, maybe you should start there.  Plus, governments and big business already know what you look like.  They already know what size your underwear is, what health problems you have, and where you like to get takeout from.  Google generally doesn't care where you are, or what you are doing.  (Not to mention they already have that information based on the location of your cell phone.) And, given the number of various types of cameras all over our world, there is a pretty good chance that you were recording by someone else at the exact same time.  In the world we live in, there is only one place that you can be sure you aren't be recorded.  Your home.  (And even that may be questionable at times.)   When you are in the bathroom you can be somewhat more assured that no one is recording you, but are you sure?  There are cases all over the place about people hiding cameras in all kinds of bathrooms around the world.

Thank you!  You brought up the bathroom issue.  I don't want someone filming my junk while I am using the can or doing something else I don't want people to see!

A few years ago, a friend showed me a video that was recorded, in secret, of a guy playing Guitar Hero at Best Buy, jumping around like a rock star would on stage.   This video was recorded on a normal cell phone camera.   For videos in the bathroom, you don't have to search very hard to find articles about the early days of cell phone cameras and people taking pictures of other naked people while in a locker room.  Yet, today, people go in to locker rooms all the time with a cell phone and it doesn't bother people much.  They may keep an eye on that person to make sure they don't do anything that appears to be taking a picture.  But, in reality it is easy enough to modify a cell phone so that it doesn't make a sound when taking a picture.

Then, there is this :

http://www.allpredatorcalls.com/i-kam-xtreme-3-0-mega-pixel-video-recording-sunglasses-4-gb-internal-memory-expandable-to-32gb-flat-black-frame-50029/?gclid=CKPvhO61t7cCFStp7AodZGQAUg

Yup, $99 for a set of glasses with a camera built in that you would probably look at and think to yourself "those are ugly" and go on your way.   If you search around, I know you can find other similar glasses that are even less obvious that you would never notice.  Basically, this problem already exists.  The main difference with Glass is that the glasses upload the images to Google, and Google never deletes anything.  So, Glass would make it easier to throw someone in jail when they went around using the camera for something it wasn't intended.  Further, with the current generation of Glass, it is plainly obvious that someone is wearing it!

But, in addition to this already being easily (and far less expensively) available, my point is that there are societal norms that people will conform to.  I have never worn my Glass glasses in to a bathroom outside of my house.  *IF* I ever did, you can be sure that I would point them at the ceiling so that they couldn't possibly be recording anything.  But, in general, I would leave them with my wife or stuff them in a bag.  I realize that not everyone would think of this, but people will eventually catch on after someone makes a comment to them in the bathroom.  In short, this is already an existing problem, but not one that people with any common courtesy would run in to.

Okay, but what about creep shots?  Guys taking pictures of girls chests (or worse) when they are unaware of it.  (Like I saw in the parody video on YouTube.)

First, please refer to the question above.  It is already easily done with existing technology in ways that are FAR less obvious.   But, I have also overheard conversations where some dude-bro was talking about how he pretended to be texting so that he could get a shot of the cans on some "hottie" across the room.  It doesn't matter if the camera is obviously pointed at you, you don't know what someone is doing and will usually not confront them unless they make a mistake that convinces you they are doing something.  Cameras are on the back of the phone, taking pictures without someone knowing is a reality in out lives.  We deal with it with cell phones, why is Glass any different?

But, I would argue that the real problem here is societal.  Why do the dude-bros think this type of behavior is okay in the first place?   The deeper issue is that they view women as objects meant to excite them.  As a male, I understand that looking at women and assessing their attractiveness is built in to us.  We all do it, and I believe it is a primal instinct that we have that was used to make sure the best genes survived in to the future.  The question is, what do we do after that?   If you don't find yourself thinking, "Gee, I bet she wouldn't be too happy that I just rated her in my mind based on how she looks." then you may want to reconsider how you treat people in general.  But, I'll get off my feminist soap box as I could easily go on and on about things like that.

Short version, people need to teach their children that everyone is a person with thoughts and feelings.  Objectifying anyone in a way they don't approve of is wrong.

But, the difference is that with Glass nobody would know you were taking a picture or recording video.

This argument is interesting, and when taken at face value doesn't work.   There are two ways to take pictures build in to Glass.  The first requires that you reach up and press a button on the frames to take the picture.  The second is to wake the device up and say, "Okay glass, take a picture".  You would notice both of these things just like you would notice someone using a phone to take a picture.

But, there is the hack out there that lets people take pictures of you just by winking.  That is more subtle, but I would bet still requires that Glass be awake before it would work.  Waking Glass up requires tapping the frame or jerking your head up.  Then, there is the issue of strange people winking at you.  And finally, see the spy glasses link above.  The problem already exists, and while I agree that it is disturbing  it really isn't a good reason not to allow Glass to exist.  Rather, Google should take this criticism to heart and make a small modification that would make a huge difference.  Put a super bright LED on the glasses that is connected to the camera with hardware such that the camera cannot be operated without the LED being on.  Most people wouldn't have the expertise to disconnect the LED in such tiny electronics.  And of the few that do, most wouldn't waste the time.   The remaining tiny percentage is people that have real issues and will do inappropriate things no matter what you try to do to stop them.

Okay, but when people have to use their cell phones to take a picture or video, there is the time needed to pull it out of their pocket before they start recording.

As I have already stated, Glass doesn't record all the time.  So, something has to be done to it to wake it up and make it take a picture.   So taking a picture with Glass probably isn't much faster than taking it with a cell phone.  In fact, there are many phones out there that have a dedicated button for taking pictures.  Those devices can probably take a picture FASTER than Glass can.

But, I also noticed something interesting while wandering around downtown San Francisco during the Google I/O 2013.  Most of the people walking around already had their phones in their hands.  Granted, there were a lot of people playing Ingress, which would account for some of it.  But, for the people that looked like they actually lived there, most of them had their phones out.  And a good number of those phones were iPhones, which currently can't play Ingress.

If you already have your phone in your hand, the time needed to take a picture usually drops.  I would argue that you may be able to take a picture faster using a phone already in your hand than reaching up, waking up Glass, and telling it to take a picture.  Add to that, the fact that even after pressing the button there is a noticeable lag before Glass takes the picture, and you may realize that for "OMG this is happening NOW" pictures you are probably still better off with your phone!

Yeah, but I heard that Glass constantly uploads your location when they are on.

Again, another argument that floors me.   First, Glass only uploads your location once every 10 minutes.  Granted, that is a setting that Google should allow people to turn on and off, but they already have that information anyway.   Your cell phone has a GPS in it, and there is nothing that would stop Google from turning it on every 10 minutes and uploading your location.  (Who knows, they may already!)  Then, there is location data from cell towers and wifi access points.   Even without turning on the GPS, you can be triangulated to a very small area for a possible location.  Small enough that it doesn't matter if it is pinpoint accurate.  They can find you if they want.   If you are REALLY concerned about this, you should turn off your phone, never use the Internet, and move out to a cabin in the woods somewhere and have no contact with the outside world.

They already know where you are, and what you are doing.  And they have tweaked the laws so that it is perfectly legal.  That ship has sailed.

Okay, but what about the ads?  I don't want ads popping up throughout my day!

In the current developer specification, showing ads is forbidden.  If a developer started to provide unwanted ads with Glass, I think it would sink the whole system.  I realize that Google makes most of its money off of advertising.  However, I think they also see that people don't want to be bugged by ads all the time.

I honestly believe that Google will continue to keep the "no ads" requirement in their apps.  Glass doesn't have a large enough screen to stick a banner add at the bottom where it is out of the way and still have it be readable.  So, ads would have to take over the whole screen for some amount of time.  Further, if ads popped up randomly throughout the day, early adopters would throw Glass in a drawer and tell people not to buy it.  I am honestly not sure how Google intends to make money off of Glass.  It is possible that the revenue they get from selling Android apps is enough of an incentive to do the same thing on Glass.  But, if Google wants Glass to be successful, they need to make it something people want to use.  Annoying ads popping up at random would kill the user experience.

 Yeah, but the glasses themselves look really stupid and ugly.

Perhaps one of the silliest comments I have heard.   I would agree that most of the time the glasses look silly.  I suspect Google agrees and that is why they are working with a sunglasses designer to make the final product look better.  However, when Glass is worn with the included sunglasses shades, they really don't look as horrible.  I wore them with the sunglasses shade today going through a drive-thru and nobody seemed to care.

Which brings me to perhaps the most important point of that argument.  If it were illegal to have bad fashion sense, many of us would already be in jail.  Further, if it were up to me to decide what looked good, most "high fashion" would land people in jail.  Fortunately, for the entire world, bad fashion choices won't land you in jail, and usually won't have people mocking you.  (Unless you are still in High School, or perhaps the fashion industry.)

We can hope that once Glass is released to the public that it looks better.  If it doesn't, that may well kill the project.

But Glass doesn't do anything my cell phone can't.  And how come Google owns the glasses even after I paid for them?

In general, I agree.  Which I consider to be an argument for why people freaking out about Glass is silly.  At the same time, I also see why it is a valid argument for not using or having Glass.   What this argument fails to take in to consideration is what state Glass is currently in.

There is a reason that existing versions of Glass cost $1500+tax.  The same reason accounts for why you are not allowed to resell them.  Not surprisingly, that same reason accounts for why the software is rough around the edges and loaning Glass is not allowed.  (Even though one of the Glass developers made a comment at I/O about asking someone with Glass if you could try it.)  Glass is not a finished product!   Google wants to get it in the hands of people that will be excited for the potential sooner rather than later.  (Which means developers.)  Those developers will experiment with things and create new apps for it.   The same developers will give feedback to Google about what is good, and what isn't.  And hopefully the final product will be better because of it!

Consider the case of Microsoft and their recently announced Xbox One.   Do a search for "Microsoft Durango".   You will quickly find out that there are a LOT of developers that had access to the development platform long before it was released.    You may even come across an article talking about the "zebra stripes" on the console.   The developers needed access to the development kits early on.  I am sure they signed agreements preventing them from letting non-developers from seeing the prototype hardware along with giving Microsoft piles of cash while the agreement said that Microsoft obtained ownership of the development kit.   In the console industry, the quantity and quality of the launch titles can really help or hurt the adoption of the new hardware.  Microsoft wants to get developers working on top quality titles as early as possible so they can be successful.  At the same time, they are giving those developers an unfinished product to work with so that they can create those titles.  Google is doing the same thing with Glass.  The high price is because so few were made, and to keep out people that probably won't contribute to the success of Glass.  It was primarily available through a developer conference so that developers would get it, and provide feedback while working on new uses for the technology.

I would almost bet money that once the final version of Glass is announced that Google stops caring if you resell the developer versions.  It is just that right now, they want to keep the audience to a group of people that will forgive them for having the software not be polished while hopefully contributing to its success.

Okay, but I don't want Google snooping on me!

The EFF recent put out a report on the privacy policies of various companies.  Of Google, Apple, and Microsoft, Google ranked the highest for privacy.   Hopefully this means that the snooping they are doing isn't as bad as other companies are. (Source : https://www.eff.org/who-has-your-back-2013 )

But, there is also something that Google has going for it.   Glass runs Android!  Given the significant number of custom Android ROMs out in the wild, it is reasonable to believe that something similar will happen with Glass.   Google also has a history of making their hardware fairly easy to unlock for people that know what they are doing.   So, I suspect that if Glass is successful there will be a vibrant custom ROM scene.  That scene will probably have at least one "anti-Google" ROM in it that strips out any reporting that Google may have put in.  And the best part is, I don't think Google will really care!



Wow.  You actually read this far!  I am impressed.  I would imagine that at this point you are either thinking, "You know, he has a point."   Or, you are so pissed off at my obvious lack of understanding of the situation that you could throw your computer out the window.  Please feel free to ask questions and make constructive comments in the comments area of this post.  If you read this whole thing, hopefully you have come away with the impression that I don't believe that Glass is a perfect product.   In addition, if Glass were released today, it would be a huge flop.  But, I would love to know what I am missing, that doesn't already exist in the world in an easier and less expensive solution, that makes Glass so scary it should be banned or hated so much?

Thursday, July 19, 2012

Code coverage with Android and EMMA

Recently, I have been looking in to tools in Android that would help me improve code quality and find bugs before putting the product out.  I picked up a copy of Diego Torres Milano's "Android Application Testing Guide" as a good place to get me started.   Since there are a lot of tools out there, and not all of them support Android, it was a useful guide to tools that should be working.

One of the tools I was looking in to is code coverage.   Over the years, EMMA has been integrated with the Android build tools, which is supposed to make it easier to use.   Unfortunately, if you don't use them just the right way they can end up being a horrid time suck trying to figure out why your instrumented build just isn't working.

For my testing, I was using the latest tools available as of this writing.  (That would be ADT 20)   Lots of the information available on the Internet is for older versions of tools that don't use the same commands as ADT 20.  I also started with the most basic app I could, and set it up so that I had an easy way to intentionally miss some code, or make sure I hit it all.   The code looked something like this :
@Override
public void onCreate(Bundle savedInstanceState) {
   String appname = "unknown.app";
   super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);
}

public void testme() {
    System.out.println("This is a test!");
}

A pretty simple "app" that mostly comes out of the Android tools when you create a new project.   The "testme()" method is there because it will allow us to explicitly call some code (or not) to let us see that code coverage is really working.

Next, I created a test app using the Android tools and created a new test case.   The test case extends ActivityInstrumentationTestCase2, as it will start up the activity we want to test in a state that is easy to use.  The test class looked something like this :

public class MyTest extends ActivityInstrumentationTestCase2 {
public MyTest()
{
   super(TestActivity.class);
}

public void testCodeCoverage()
{
}

The "TestActivity" referenced in the above code is the name of the Activity that we created earlier.   Also, note that our test doesn't actually do anything.   For now, this is okay.   When the MyTest class is run, ActivityInstrumentationTestCase2 will create the activity, which will result in the onCreate() method being called.   So, once we have our code coverage running, we will have a block of code that was covered, and a block that was not.

At this point, we are going to use the command line.   We also need to make sure that we have a fairly current version of Apache Ant ready to use.   For my tests I was using 1.8.2.

At the command line, we want to convert our apps to use Ant for building.   To do this, we need to use the "android" command that is included in the SDK.  (On Windows, it is "android.bat")  We need to run two commands, one to convert the "TestActivity" app and one to convert the "MyTest" test project.  The command will look something like this :

android update project --path /path/to/TestActivityProject --name TestActivityProject --target android-16
The "--name" parameter should be set to whatever you named your project, and "--target" should be set to the API level that you want to test with.   The "--path" parameter requires the FULL path name to your project.   So, if you are on windows it might be something like "c:\users\foo\workspace\TestActivityProject" I tested with an Android 4.1 VM, so I chose "android-16".  The version you use isn't too important, unless you plan to use Ant to make your final builds.

Next, to convert the test project :

android update test-project --main ../TestActivityProject --path /path/to/MyTestProject
The "--main" parameter confused me a bit at first.   It should be a relative path from the directory you store "MyTestProject" in, to the path of "TestActivityProject".   If you are using Eclipse and putting your code in a workspace, you should normally need to use ../.

Finally, we are ready to build and run our test.  Go in to the directory for "TestActivityProject" and run "ant".  (If ant isn't in your path, you may need to use a full path to ant instead.)

But, whats this?  We get a help screen like the following :


Android Ant Build. Available targets:
   help:      Displays this help.
   clean:     Removes output files created by other targets.
              The 'all' target can be used to clean dependencies
              (tested projects and libraries)at the same time
              using: 'ant all clean'
   debug:     Builds the application and signs it with a debug key.
              The 'nodeps' target can be used to only build the
              current project and ignore the libraries using:
              'ant nodeps debug'
   release:   Builds the application. The generated apk file must be
              signed before it is published.
              The 'nodeps' target can be used to only build the
              current project and ignore the libraries using:
              'ant nodeps release'
   instrument:Builds an instrumented package and signs it with a
              debug key.
   test:      Runs the tests. Project must be a test project and
              must have been built. Typical usage would be:
                  ant [emma] debug install test
   emma:      Transiently enables code coverage for subsequent
              targets.
   install:   Installs the newly build package. Must either be used
              in conjunction with a build target (debug/release/
              instrument) or with the proper suffix indicating
              which package to install (see below).
              If the application was previously installed, the
              application is reinstalled if the signature matches.
   installd:  Installs (only) the debug package.
   installr:  Installs (only) the release package.
   installi:  Installs (only) the instrumented package.
   installt:  Installs (only) the test and tested packages (unless
              nodeps is used as well.
   uninstall: Uninstalls the application from a running emulator or
              device. Also uninstall tested package if applicable
              unless 'nodeps' is used as well.

This is where I really screwed up and spent a lot of time scratching my head.   Since we want to use EMMA, we need an instrumented build, right?   So the command that we need is "ant emma instrument install test" to get a build, install it, and run the test in it.

While this seems like the most intuitive answer, you will quickly find out that it doesn't work.  Everything will compile and install fine, and we can assume that the resulting apps are instrumented.   However, when it gets down to running the test, you will be greeted with something like this :


     [echo] Running tests ...
     [exec] INSTRUMENTATION_RESULT: shortMsg=java.lang.IllegalAccessError
     [exec] INSTRUMENTATION_RESULT: longMsg=java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation     [exec] INSTRUMENTATION_CODE: 0

Hmm..  Something didn't work.  This is where I spent a ton of time trying different combinations and searching to understand what was going on.   Finally, as I was giving up, I noticed a browser page that I had already opened that said for EMMA code coverage, we need to run "ant emma debug install test".  I didn't think it would work, but I gave it a shot.  Crazy as it is, it DID work!  (I literally spent 7 hours trying to figure out what the above error message was all about.)

Once your instrumented build is run, the necessary coverage files will be downloaded, and a coverage.html file will be created in your test project's "bin" directory.   Opening that up should show that your onCreate() method ran all of its code, but the testme() method wasn't touched at all.   If you go in to the testCodeCoverage() method in the test app, you should be able to add the line "getActivity().testme()" and then run the instrumented build again.   This time, you should get 100% code coverage.

Hopefully, this post saves someone out there a significant portion of their time getting started with code coverage!

Sunday, October 17, 2010

Fancy List Items in a ListView

A while ago, I was working on a project where I wanted to be able to have Android show a ListView, with custom entries in the list. In most other languages and toolkits, doing this is a bit of a pain. You have to implement a special painter to pain the list cell in just the right way. Unless you are a pretty die-hard developer for that toolkit you may find yourself horribly confused as to how to handle the situation.

Fortunately, Android made this REALLY easy. If you know how to do a layout for a form, you know almost everything you need to know in order to make a fancy list item.

First, you want to create a small layout that specifies how a single list entry should look. For my purposes, I wanted to have a single line of large text, with smaller text below. I also wanted the large text to be bright white, and the smaller text to be a darker gray color. Finally, the smaller text should be indented on both sides to indicate that it is subordinate to the larger text.

No problem! A basic linear layout will do the job nicely. My final layout looks like this :


<linearlayout android="http://schemas.android.com/apk/res/android" layout_height="wrap_content" layout_width="fill_parent" orientation="vertical">
<textview layout_height="wrap_content" id="@+id/LargeText" text="Large Text" textcolor="@color/white" textsize="25dip" layout_width="fill_parent"></textview>
<textview layout_height="wrap_content" layout_width="fill_parent" layout_marginright="10dip" layout_marginleft="10dip" id="@+id/SmallText" text="Smaller Text" textcolor="#c0c0c0"></textview>
</linearlayout>


Easy enough. Now that we have that, we need to actually write some code that will use it. I find it easiest to create a convenience class that lets me manipulate the list easily. So, I create a class called MultiLineList, that looks something like this :


import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.widget.SimpleAdapter;

public class MultiLineList {

private ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
private Activity parentActivity;
private SimpleAdapter taskAdapter;

public MultiLineList(Activity parent)
{
parentActivity = parent;

taskAdapter = new SimpleAdapter(parentActivity, list,
R.layout.multi_item_layout, new String[] { "largetext","smalltext" },
new int[] { R.id.LargeText, R.id.SmallText } );
}

public void clear()
{
list.clear();
}

public void addItem(String largeText, String smallText)
{
HashMap<String,String> item = new HashMap<String,String>();
item.put("largetext", largeText);
item.put("smalltext", smallText);
list.add(item);
}

public SimpleAdapter getData()
{
return taskAdapter;
}
}


In the constructor, we create a SimpleAdapter that we use to map our text in to the different rows of the list view we will show the user. "R.layout.multi_item_layout" is the name of the layout we created above. (You may need to change this if you called your layout something else.) The two strings, followed by the two ints give us a mapping in a hash table for how to identify the two different TextEdits that we put in the layout. There is nothing special about only having two items. We could easily have 10 strings and 10 matching ints. What is important is that each string has a corresponding int that maps to a text edit in your layout.

The addItem() method is where the good stuff happens. As part of creating the SimpleAdapter in the constructor, we told it to use the "list" variable to get its data out of. So, the addItem() method allows us to easily put new text in to the list to be used. So, calling addItem("I am big", "I am not") would give us a single entry in the list view that contained the text "I am big" in the large font, and "I am not" in the small font.

Now that we have all of the ground work in place, it is time to put the pieces together. Moving forward, I am going to assume that you have a basic form set up with a list view configured in it. Also, that a ListView variable points to it called "listView". From there, using our fancy list widgets would look something like this :


myList = new MultiLineList(this);
myList.addItem("Large 1", "Small 1");
myList.addItem("Large 2", "Small 2");

listView.setAdapter(myList.getData());



Now, the next time out list view is drawn, it will contain two items in the list. The first one will have "Large 1" in the larger text, and "Small 1" in the smaller text. The second one will contain "Large 2" in the larger text, and "Small 2" in the smaller text.

From this simple example, you should be able to easily expand your list items to contain any just about any widget type you would want. But, I leave that up to you to experiment with.

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.