Archive for the ‘Uncategorized’ Category

Sprite Fun: updated!

Since my previous post, the official development environment for Android changed from Eclipse (with a plugin) to Android Studio. The Sprite Fun game I made still works — if anything maybe it’s a little simpler.

The instructions are as follows:

  • Download and install Android Studio
  • Create a new project with type “Empty Activity” (the default)
  • In the src folder, replace the MainActivity.java with the MainActivity.java from this example, and add the two other classes from this example in the same package (changing the package name to match the package name you chose when creating the project).
  • Add the default green Android icon as an image that the app can use:
    • Select File > New > Image Asset
    • In the wizard, select “Asset Type” > “Image” and change the name to “greeny”
    • click “next” and then “finish”.

Then you’ll have a fun app that’s very simple to understand and extend — to help kids teach themselves real application programming in a real development environment!

Here are the java source code files for this example: SpriteFun2.zip

Have fun!

Carol Hamer, PhD, CTFL

I just received my official certificate in the mail from the American Software Testing Qualifications Board certifying that I’m now a Certified Tester, Foundation Level. The funny part is in the letter where it says that I’m now entitled to put the letters “CTFL” after my name on my business cards and letterhead. No offense to the ASTQB (and ISTQB) folks, but the test is really easy, so I’m not sure how impressive it will look (especially following the old “Piled Higher and Deeper”).

That said, I felt the ISTQB course was fun and worthwhile. I was working for a QA consulting company in Switzerland, and instead of taking a formal course, the employees organized an informal study group. One colleague divided the syllabus into lessons, and then we met once per week to discuss that week’s assignment. Most of the concepts in the Foundation Level syllabus are the type of things that are simple (once you read them) but you might not have thought of spontaneously. So it’s interesting to get together among colleagues and discuss. For someone like me (who has primarily seen QA from the outside, while working in development), it’s useful to take the time to understand QA from the high level concepts to the practical techniques.

I didn’t take the test with the rest of my “class” because I left Switzerland before we were done. But since the ISTQB is an international board, it was simple to just take the test after arriving in the U.S.

Fun with mobile blogging!!!

I just noticed this past weekend that I can read this blog from my handset!!!

mobile java blog

The cool thing is that if you’re reading this on your handset right now, you can click on this link to my games page and from there download the sample games and programs right onto your handset and try them out!!!

I’ve made a new HTML version of my games page (the above link) since my current handset is capable of reading and displaying html. For those whose handsets support only WML (not HTML), I have two WML pages available that link to the same sample programs: http://frog-parrot.net/hello.wml and http://frog-parrot.net/checkers.wml. Please feel free to link to any of these pages.

Even though I’m now mobile-blogging 😉 , it somehow feels like I’m not getting the complete mobile blogging experience since I’m only reading the blog from my handset (posting from my hopelessly non-mobile PC…)

I could probably remedy this by using some tips from this introduction to mobile blogging article by

I’m a little skeptical of this idea since the most interesting photo blogs tend to be written by serious photo hobbyists (if not professional photographers) who have real cameras. And in my own case, I’ve mostly been posting photos of my handset, which are tricky to take using the handset’s built in camera… But who knows? Maybe this idea will become popular.

Actually I’m tempted to combine this “mobile photo blog” idea with the following handset bug I read about recently:

Q: My Nokia 6131 keep taking photos whilst in my pocket – Why?

A: Unfortunately the camera button is on the side of the handset and there is no lock for this. this cannot be changed.

Lots of handsets have strange bugs, so I don’t know why I find this one so hilarious. “My handset keeps taking pictures of the inside of my pocket!” “Um… There’s nothing we can do about that, sorry.” lol

I think this would make a great experimental / performance art blog: “photosMyHandsetSpontaneouslyTookOfTheInsideOfMyPocket.wordpress.com”

Don’t any of you steal this idea before I get around to doing it. 😉

SMS Checkers!!!

My SMS checkers game is done and now available!!! Try it out!!!

Just go here to download it free onto any MIDP 2 phone:

http://www.frog-parrot.net/checkers.wml

This version is a big improvement on the original. First of all, it’s a peer-to-peer game — relying entirely on exchanging SMS messages from one handset to the other — so any two people who both have the game installed can play it without worrying about whether a central server is up and running and accessible. The server wasn’t doing much more than routing the game moves from one handset to the other, so it was fairly easy to write it out of the picture.

Each move requires sending a whole SMS, yet the move data typically takes no more than five bytes. It seemed like such a shame to waste the rest of the SMS payload, so I added a “taunt” feature so that you can send your opponent a message along with your move if you like!!!

Another new feature is that the game can now recover from a pause — so you can receive a call and then return to the checkers game in progress.

Additionally I did a bunch of refactoring. The original game logic was great, but the meta-logic — the game state, whose turn it is, etc. — was too intimately tied to the communications/networking code. That makes for smaller code, but the game is already pretty small (16K). So I modularized it a bit, making separate classes for the game state logic and the communications code. Ah, with a personal project you get the luxury of taking the time to refactor the code when there’s a change in requirements! 😉

If you try this game, please feel free to post any comments about it, suggested improvements, etc. Thanks.

Troubleshooting blues…

“Why won’t my MIDlet connect with my Servlet?”

It’s such a simple question, isn’t it?

Unfortunately, there are so many layers of communication and so many places to make a little (yet fatal) error, that there’s no simple answer that solves the problem every time.

In my experience, establishing the initial “hello world”-level back-and-forth communication between the client and the server is one of the most frustrating steps in client-server programming. Once you’ve established a complete and correct communication circuit, you’ve got your foundation to build on. Before that — even if you know your networking and protocols well — you’re kind of tossing your message into the black void and hoping it comes out the other side…

But troubleshooting — tracking the problem down wherever it may be — is something every good engineer should be ready and able to do. So let’s talk a little bit about strategies for narrowing down where the problem may lie in a simple case such as a MIDlet that fails to connect with a Servlet via HTTP.

1. Does it work locally, on the simulator?

Getting it running on the WTK simulator is the first step to making sure it isn’t your MIDlet or Servlet that are the problem. Unfortunately, even if it works on the simulator, it still may be that your MIDlet is wrong. Sometimes the WTK is excessively lenient about things that your handset might not like such as reading the body of the message before getting the response code.

If it’s not even working on the WTK, what can you do?

As a general rule, at this point, I would strip my example down to the simplest possible example — a servlet that returns “hello world” and a MIDlet that displays the response code and the message recieved — to reduce the number of places where things can go wrong.

Be sure you know where your server logs are, and check them for clues. Try your URL in your browser and see what the browser returns. If you’re running the client and server on the same machine, you can substitute 127.0.0.1 for the IP address to see if it’s some sort of routing issue. If none of that yields any response from the server, try your server’s “Hello World Servlet” tutorial.

On the client side, note that the WTK has a built-in profiler. You can find it under Edit > Preferences > Monitor > Enable Profiling. This will display for you the raw data exchanged between the client and the server. I’m a little wary of this profiler because it starts some processes that sometimes interfere with installing a MIDlet using Project > Run via OTA for some unexplained reason, but when you really need it, the profiler is useful.

Now, let’s suppose it’s working on the WTK simulator but not on the handset.

2. Can the handset successfully make any HTTP communications from Java?

Generally a handset has a configurable profile which gives information regarding proxy servers and whatnot that tells how to get from the operator’s network to the open Internet. Sometimes the handset has a separate profile for Java and for WAP. They’re usually careful to make sure the WAP profile is right, so if they’re separate, one thing to do is to copy the data from the WAP profile to the Java profile, if you can find the right menus to do it…

One way to check if your Java profile is correct is to try some other working MIDlet that makes a connection via HTTP. For example, I ran the MobileZoo MIDlet the other day, and it succeeded in contacting MobileZoo, so I know that my handset is correctly configured to use HTTP from Java.

3. Is the server accepting requests from the outside?

You know the old story: internal routing is different from external routing, and those lovely firewalls… Try your URL on a computer outside of your local network.

Now once you’ve done all that, it should work!!!

Unfortunately for my “Hello World” MIDlet/Servlet it doesn’t…

I think we’ve narrowed it down to the fact that I’ve set up my server to use a non-standard port for HTTP, and some step in the network chain doesn’t like it.

Hopefully it will be up and running this weekend. I’ll keep you posted!!! 😀

JSRs galore!!!

One of the things I had to learn about when I switched from programming Enterprise Edition Java to Mobile Edition was Java Specification Requests. Of course I was vaguely aware of JSRs and the Java Community Process as en Enterprise Edition programmer, but I didn’t really have to deal with them much in my daily life. (This was back in the old days when it was called “J2EE” 😉 )

But when you’re programming for mobile phones, as much as you’d like it to really be as simple as “write once, run anywhere,” devices unfortunately vary in implementation (behavior) as well as in terms of which standard (optional) APIs are available. So you get to know your JSRs, and keep track of which ones your program needs in order to run.

The very first new thing I wanted to try on my new Sagem my700x was to write a simple program to tell me which JSRs are available for me to play with. This info is probably available through everyone’s best friend (Google), but you’d probably have to dig around for it. Normally the specs you find on the Internet (like here) will tell you if the handset has Java, and whether it’s MDIP 1 or MIDP 2 and not much more. That’s okay, because it sets us up for a fun little exercise!!!

Let’s make a simple MIDlet to find out what JSR APIs are implemented on this handset!!!

It’s maybe not realistic to check for all possible JSRs, but at least we can check for the ones that are implemented in the WTK. Running the ktoolbar application and selecting the “Settings” button (after opening a new project), I get a window that lists the following optional JSRs: JSR 75 (PIM), JSR 75 (File Connection), JSR 82 (Bluetooth), JSR 135 (Mobile Media), JSR 172 (Web Services RMI), JSR 172 (Web Services SAX), JSR 184 (3D Graphics), (JSR 205 Wireless Messaging).

I looked them all up here and downloaded the final draft documentation for each one.

The next step was to write a MIDlet that attempts to load a class from each optional package. I assume that if one class is there, the whole package is probably there too. For fun I decided to check for MobileScope’s EGE API as well!!! 😀

The result on the WTK was exactly as expected: all of the above APIs are supported except MobileScope’s EGE API.

Here’s the result for the Sagem m700x:

JSR 75 PIM: supported,
JSR 75 File Connection: supported,
JSR 82 Bluetooth: not supported,
JSR 135 Mobile Media: supported,
JSR 172 Web Services RMI: not supported,
JSR 172 Web Services SAX: not supported,
JSR 184 3D Graphics: supported,
JSR 205 Wireless Messaging: not supported,
EGE: supported.

If you’d like to try the MIDlet on your own handset, I’ve put it on my site here: http://www.frog-parrot.net/hello.wml

Here’s the code:


package net.frog_parrot.test;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form ;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.MIDlet;
/**
* A simple MIDlet to test which APIs are implemented.
*/
public class Test extends MIDlet implements CommandListener {
  
  private Command m_exitCommand = new Command("Done", Command.EXIT, 1);
  private List m_menu;
  private Form m_resultScreen;
  /**
   * The list of API labels.
   */
  private String[] m_jsrs = {
    "JSR 75 PIM",
    "JSR 75 File Connection",
    "JSR 82 Bluetooth",
    "JSR 135 Mobile Media",
    "JSR 172 Web Services RMI",
    "JSR 172 Web Services SAX",
    "JSR 184 3D Graphics",
    "JSR 205 Wireless Messaging",
    "EGE",
  };
  
  /**
   * The index constants for the label array.
   */
  private static final String SUPPORTED = "Supported";
  private static final String NOT_SUPPORTED = "Not Supported";
  private static final int JSR_75_PIM = 0;
  private static final int JSR_75_FC = 1;
  private static final int JSR_82_BLUETOOTH = 2;
  private static final int JSR_135_MOBILE_MEDIA = 3;
  private static final int JSR_172_WEB_SERVICES_RMI = 4;
  private static final int JSR_172_WEB_SERVICES_SAX = 5;
  private static final int JSR_184_3D_GRAPHICS = 6;
  private static final int JSR_205_WIRELESS_MESSAGING = 7;
  private static final int EGE = 8;
  
  /**
   * Empty constructor.
   */
  public Test() {
  }
  
  /**
   * Initialize the Displayables.
   */
  public void startApp() {
    m_menu = new List("Test Menu", List.IMPLICIT, m_jsrs, null);
    m_menu.addCommand(m_exitCommand);
    m_menu.setCommandListener(this);
    Display.getDisplay (this).setCurrent(m_menu);
    m_resultScreen = new Form("Results");
    m_resultScreen.addCommand(m_exitCommand);
    m_resultScreen.setCommandListener(this);
  }
  
  public void pauseApp() {
  }
  
  public void destroyApp(boolean unconditional) {
  }
  
  /**
   * Change the display in response to a command action.
   */
  public void commandAction(Command command, Displayable screen) {
    if(screen == m_menu) {
      if(command == m_exitCommand) {
        destroyApp(false);
        notifyDestroyed();
      } else {
        m_resultScreen.deleteAll();
        int index = m_menu.getSelectedIndex();
        switch(index) {
        case JSR_75_PIM:
          m_resultScreen.append(m_jsrs[JSR_75_PIM] + ": ");
          try {
            Class.forName("javax.microedition.pim.PIMException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_75_FC:
          m_resultScreen.append(m_jsrs[JSR_75_FC] + ": ");
          try {
            Class.forName("javax.microedition.io.file.ConnectionClosedException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_82_BLUETOOTH:
          m_resultScreen.append(m_jsrs[JSR_82_BLUETOOTH] + ": ");
          try {
            Class.forName("javax.bluetooth.BluetoothConnectionException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_135_MOBILE_MEDIA:
          m_resultScreen.append(m_jsrs[JSR_135_MOBILE_MEDIA] + ": ");
          try {
            Class.forName("javax.microedition.media.MediaException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_172_WEB_SERVICES_RMI:
          m_resultScreen.append(m_jsrs[JSR_172_WEB_SERVICES_RMI] + ": ");
          try {
            Class.forName("java.rmi.RemoteException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_172_WEB_SERVICES_SAX:
          m_resultScreen.append(m_jsrs[JSR_172_WEB_SERVICES_SAX] + ": ");
          try {
            Class.forName("org.xml.sax.SAXParseException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_184_3D_GRAPHICS:
          m_resultScreen.append(m_jsrs[JSR_184_3D_GRAPHICS] + ": ");
          try {
            Class.forName("javax.microedition.m3g.CompositingMode");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case JSR_205_WIRELESS_MESSAGING:
          m_resultScreen.append(m_jsrs[JSR_205_WIRELESS_MESSAGING] + ": ");
          try {
            Class.forName("javax.wireless.messaging.SizeExceededException");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        case EGE:
          m_resultScreen.append(m_jsrs[EGE] + ": ");
          try {
            Class.forName("com.infusio.ege.toolkit.TLV");
            m_resultScreen.append(SUPPORTED);
          } catch(ClassNotFoundException e) {
            m_resultScreen.append(NOT_SUPPORTED);
          } catch(Exception e) {
            m_resultScreen.append(e.getClass()
                                  + ": " + e.getMessage());
          }
          Display.getDisplay(this).setCurrent(m_resultScreen);
          break;
        default:
          break;
        }
      }
    } else {
      Display.getDisplay (this).setCurrent(m_menu);
    }
  }
}

Did I say Sagem myX700?

It’s written right on the handset my700x!!!

Dyslexics of the world, untie!!! 😉