Showing posts with label datepicker. Show all posts
Showing posts with label datepicker. Show all posts

Sunday, September 30, 2012

Intel Atom emulator crashes with DatePicker

I love the new Intel Atom (x86) emulator for Android development. It starts up quickly and runs at real hardware speeds. I did have one big issue, every time I brought up a view with a DatePicker control in it the emulator would crash to the desktop. Not acceptable.

Running the same code on my phone or in the emulator using ARM worked like a champ. So what should a developer do? This is a bug in the emulator code, not my code. Doing a little research shows that it could be the hardware acceleration at fault. You can shut that off with a setting the android:layerType="software" in your XML file or with a call to setLayerType(View.LAYER_TYPE_SOFTWARE, null); 

The problem is I am developing my app for 2.2 and beyond. That call does not show up until a much later version of the Android platform. Time for some reflection.

Add the following as a new file to your project


import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.graphics.Paint;
import android.view.View;

public class NewerMethods {
    private static Method LayerType;

    static {
        initMethods();
    }

    private static void initMethods() {
        try {
            LayerType = View.class.getMethod("setLayerType", new Class[] {int.class, Paint.class});
            /* success, this is a newer device */
        }
        catch (NoSuchMethodException nsme) {
            /* failure, must be older device */
        }
    }

    public static void setLayerType(View view, int layerType, Paint paint) throws IOException {
        try {
            if (LayerType != null) {
                LayerType.invoke(view, layerType, paint);
            }
        }
        catch (InvocationTargetException ite) {
            /* unpack original exception when possible */
            Throwable cause = ite.getCause();
            if (cause instanceof IOException) {
                throw (IOException) cause;
            }
            else if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            }
            else if (cause instanceof Error) {
                throw (Error) cause;
            }
            else {
                /* unexpected checked exception; wrap and re-throw */
                throw new RuntimeException(ite);
            }
        }
        catch (IllegalAccessException ie) {
            System.err.println("unexpected " + ie);
        }
    }
}

Add the following to your onCreate method of the Activity that uses a DatePicker in its view. I have it right after my call to setConventView(...)


        try {
            NewerMethods.setLayerType(findViewById(android.R.id.content), 1, null);
        }
        catch (IOException e) {
            // Just doing this on newer stuff to avoid emulator crash
        }
        
I know, I am using a magic number in the call. I can't use View.LAYER_TYPE_SOFTWARE because Eclipse has no idea about it when compiling 2.2 code.

This allows my code to run just fine in the emulator. I am running 2.2 code in a 4.0.3 emulator as that is the super fast Intel based emulator. I also run the code on my actual 2.2 phone from time to time to make sure everything is fine. Just easier to stick on the computer using the keyboard and mouse while doing initial development and only test on hardware as needed.

Tuesday, October 25, 2011

Fun with Android DatePicker and 1970

I was doing a new round of testing on our Android tablet. The application is used for medical information entry and one of the fields is date of birth. It has been working like a champ on the phones using 2.01, 2.2, 2.3 but on the tablet running 4.1 you could not enter anything before 1970. You could type in 1963 and it would set it back to 1970 and the [-] button would disappear.

I totally get why it stops at 1970 as that is the epoch year used for all sorts of things in computers. Obviously the Android team changed a default in later versions of the SDK. My phone, running 2.2, allows you to go back to 1900.

After some research I found a solution that works for all devices I have tested against. In my XML file I added android:startYear="1900" to my definition. If you look in the latest documentation they discuss android:minDate but that is only available in later version of the SDK.

Before I stumbled upon startYear I tried to use reflection to call the setMinDate(long) on the datepicker but I did not have any luck doing that. I am really happy that was not the solution. I would much rather use something in the XML that solves it on all platforms.

Of course after I did this SVN got confused about a directory already being locked and would not allow me to check in the change. I found Team -> Cleanup in Eclipse solved that issue.

Now that I have my new "set favorites" processing in place on the Android I need to convert all that work over to the iPhone / iPad. Research time as some of it just does not have a direct translation to iOS and while the menu system is possible on the iPad it is officially not supported on the iPhone so I am going to have to come up with a work around. The first menu system I found has caused apps to be rejected by Apple due to private method usage making it a non-option. Dual iOS / Android development has a lot of headaches.