Hidden methods in Sony Ericsson Java Platform

It is no secret that the published interfaces for MIDP classes in any JavaME Platform is only a subset of what in reality is there. Most of the native calls needed to interact with the underlying native platform, and other helper methods, are hidden from us. Mostly for good, and sometimes for bad…

The Anecdotal History

We are developing a custom application framework on top of MIDP, adding a MVC application model, and modern interface components with touch and animation support. All this is build on top of a shared subclass of Canvas, and our own custom drawing with screen transitions, etc. is implemented on top of that.

An interface component is called a View, and any interface component that can host other interface components implements the ViewParent interface. Simple until I introduces the method hasFocus(). All of a sudden the application refused to run on target Sony Ericsson device. The emulator worked nice, our P1i worked, even the Xperia X1 run. But none of the cybershots, or walkmans with JP-7 or JP-8.

“Application error“. Oh well, that means that something threw an exception during the MIDlet constructor or appStart() call. So add pedantic catches, and display the error in an Alert; “NoClassDefFoundError”.

The Problem

NoClassDefFoundError on the OSE phones, but no other installed with the same jad/jar-files, that is strange. Unfortunately Sony Ericsson has a policy of removing all error messages from exceptions, so no clue as to what class is missing either. Turn off Proguard optimization, still does not work, still NoClassDefFoundError. Head back to the Subversion logs and binary search, what is the latest revision that worked? And what was changed?

Turnes out that the shared Canvas subclass that implement the aforementioned interface ViewParent got the new method hasFocus(), and that is the only change from the working revision, to the broken revision.

– “I’m pretty sure that is working.”, one of the half dozen bug-hunting team member said looking at:

public boolean hasFocus() {
    return true;
}

As it turns out the platform implementation of the MIDP class Canvas has a hidden method named hasFocus(). It is not private, but declared as public and final, but not exposed in the public API. So when our subclass is loaded, our public hasFocus() method clashes with the unexposed public final hasFocus() of the platform’s implementation.

Solution, and Lesson Learned

The method hasFocus() was renamed to isInFocus(), and now everything works again.

From now on we will:

  • Never trust subclasses of MIDP classes.
  • Test on device early and often, also for obvious changes.
  • Always keep commits small and atomic.

Leave a Reply