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.

Thursday, September 20, 2012

Xcode 4.5 iOS 6 iPhone 5 simulator issues


Last night before I left I begin the Xcode 4.5 official release download. This morning it was ready to roll and then it needed to update a few other areas of Xcode but it was up and running pretty quickly. I then went about the work of having my app make use of the full height of the iPhone 5 screen.

Xcode asked if I wanted to add the Default-568h@2x.png which I allowed it to do. I knew that was one of the requirements so I was very happy it created the all black image for me. Our launch time is super fast so I don't need a real launch image.

Next I knew the rotation messages needed a massage. I add the following lines to all the ViewControllers allowing all orientations to work.

// OS 6 rotate message
- (BOOL)shouldAutorotate {
    return YES;
}

// OS 6 rotate message response
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

I left the original orientation code in place for non-iOS 6 devices. 

Time to tweak the rootViewController

    // Changed for iOS 6
    self.window.rootViewController = self.navigationController;
//  [window addSubview:navigationController.view];


I had to switch to libxml2.2.dylib for libxlm.2.2.7.3.dylib for my frameworks. Not sure why the newer Xcode has what appears to be an older version of this lib but everything appears to work using it.

I download older simulators (4.3 and 5.1) so I can test as many as possible without swapping devices.

Adjusting the home screen paint for extra size by checking for iPhone 5 resolution and putting our logo below the grid of buttons on the portrait version makes that look nice. Putting extra space between each icon on landscape mode to space them evenly across the screen gives that area the proper look.

All the other screens filled the new height and went smoothly and things look great except for one big issue I have not yet been able to resolve. The back button in the navigation bar does not work in the simulator. Well it does work for everything but an iPhone (Retina 4-inch). I can choose iOS 4.3, 5.1 or 6.0 and any device - iPhone, iPhone (Retina 3.5-inch),  iPad, iPad (Retina) - and everything about my program works just fine. Once I set the hardware to be iPhone (Retina 4-inch) then the buttons will not work. Nothing happens when I click on them, no errors, no highlighting, no action at all.

Seems to me I am not having an iOS 6.0 issue but a simulator issue. Until I get my hands on some real hardware I am not sure what to do. I can install iOS 6.0 on my iPad 2 or my third gen iTouch but that does not tell me if things have gone haywire on a real iPhone 5.

The other area of fun is two of my hardware testing devices are no longer supported by Xcode 4.5. I can't use the second generation iTouch or the iPhone 3G. They are both stuck at iOS 4.2.1. We checked our logs and it appears we still have a user with that flavor of iOS. If I update the software I would set 4.3 as the minimum. Users would either stick with the version they have, upgrade their iOS if possible or buy new hardware. Apple is sort of forcing things along in this area. Even the original iPad has hit the end of its upgrade cycle.

At this point I get to keep digging to find out why the simulator is not letting me press the back button or the menu button I have at the other end of the navigation area on the 4" iPhone. Pretty obvious that I will not even think of releasing a new cut of the program until this is resolved. Sure, the simulator can be hosed as long as the code runs on a real device I will be fine. I really am hoping it is a code tweak to make it work across the board. Right now 4" iPhone information is pretty sparse.

** UPDATE ** Not fixed but I did try rotating the screen in the simulator. The buttons started to work. Then I rotated again and they stopped, then again and the back button would work but not the menu button. At times all buttons will work then will stop working. Rotation may or may not allow them to work again. I really does appear the simulator has an issue in this area.

** FIXED ** I had to open my MainWindow.XIB file, select the Window object and ticked "Full Screen at Launch". Now everything appears to be working on all simulator devices. I need to beat on the application for a bit more but now I at least feel safe checking in the code changes I have made. Hope this knowledge can help out someone else.

Monday, September 10, 2012

Mobile Native vs. HTML 5 - can't hide your JavaScript code

I have the scheduler viewer running in HTML 5. It scrolls around and paints rather nicely. Performance of the HTML 5 canvas control is acceptable on various devices. I had fun experimenting with the Canvas control but one thing really bothers me - anyone can grab my JavaScript code. Sure I could obfuscate it and make it a little more difficult to us but it is still there in your browser ready to steal. A pretty printer will reformat the code to be readable with silly looking variable and method names.

This is just a little sample app so I don't really care too much about this code but what if the code is logging in to your server and making a lot of API calls? Better not do all of that in JavaScript. That means you need to hide things on the server side. Basically you need to move a bulk of the work up there so others can't have free reign on your data. That puts more of a load on your server instead of on the client. We don't want slow clients but JavaScript has really stepped up its processing speed so putting what you can on the client makes sense.

I ran into this situation at a previous company. We wanted to do an HTML interface to our stock market data. Some one looked over the code as it was sent to their PC, figured out most of the API and started grabbing the 20 minute delayed stock market data off our feed. They were not using the API correctly and crashing our server. Going through all the fun of legal was really dragging out so we explain to the thief how to use the API to stop crashing the server. I was not involved in all the legal aspects so I don't know the full story or the final resolution. Given enough time we probably could have gotten the server to not crash and to obfuscate the API even more but that generally turns into a losing battle.

With a Native Mobile App this is much less likely to occur. Yes, you can sniff the wire and try to emulate the calls that way. People will do that. You can use HTTPS instead of HTTP which helps. It really is a lot harder to figure out an API from an App though, you just don't get to see the source code.

This does not make HTML 5 + JavaScript the wrong way to go. This does make you really think about JavaScript if you are accessing a lot of data off your server. If you are just doing an interactive web site, a game or something else where the loss of data is really very minimal and you don't mind others scanning your source code then go for it.

Before you decide HTML 5 is the way to go for a mobile project think about your level of source code exposure. Decide how much you need to handle on the server. Decide what code is harmless for others to see on the client side. Don't go in blind and try to solve these issues the week before your first release.

Thursday, September 6, 2012

Convert Numeric keypad [ENTER] to [TAB] in java

Our data entry staff does a lot of numeric entry. Java uses the [TAB] key to move between entry fields. I was asked if we could have the NumPad [ENTER] key act like the [TAB] key greatly speeding up data entry. I was able to pull it off with a little bit of code.


import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.KeyEvent;

/**
 * Special event queue to convert NUMPAD + ENTER into TAB
 *
 * @author kevin.peck
 * @date Sep 4, 2012
 */
public class CustomEventQueue extends EventQueue {
    private Robot robot;
    private boolean swapKeys;

    /**
     * Constructor
     *
     * Get robot running so we can fake key events
     */
    public CustomEventQueue() {
        super();
        try {
            robot = new Robot();
        } catch (AWTException e) {
            System.out.println("Unable to get robot running " + e);
        }
    }

    /**
     * @param swapKeys  true to force key swap processing
     */
    public void setSwapKeys(boolean swapKeys) {
        this.swapKeys = swapKeys;
    }

    /**
     * @return  true if we are doing key swap processing
     */
    public boolean areKeysSwapped() {
        return swapKeys;
    }

    /**
     * Watch for keyevents and convert NUMPAD ENTER key into TAB key
     */
    @Override
    protected void dispatchEvent(AWTEvent event) {
        if (swapKeys && event instanceof KeyEvent) {
            KeyEvent keyEvent = (KeyEvent)event;
            if (keyEvent.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD && keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
                if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
                    robot.keyPress(KeyEvent.VK_TAB);
                    robot.keyRelease(KeyEvent.VK_TAB);
                }
                return;
            }
        }
        super.dispatchEvent(event);
    }
}

Add this to your main code (class derived from JFrame)
    private CustomEventQueue eventQueue = new CustomEventQueue();

Add this to the constructor or initialization routine of the class derived from JFrame
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                EventQueue ev = Toolkit.getDefaultToolkit().getSystemEventQueue();
                eventQueue.setSwapKeys(true);
                ev.push(eventQueue);
            }
        });

Why is there a setSwapKeys() method? So you can turn off this functionality. I set enabled the sample above but in my code it is actually reading a Preference setting. You can enable / disable the [ENTER] = [TAB] at any time in your code by invoking the swap keys method.

If swap keys is enabled I eat the VK_ENTER from the numeric keypad for both PRESSED and RELEASED events. I use the Robot object to send out a VK_TAB press and release on the PRESSED event. Nothing is sent on the VK_ENTER RELEASED event. 

Why am I installing the queue invokeLater? I was not doing that an it ran just fine on Java 1.7 but on Java 1.6 I would get an exception. Putting it on the EDT solved that issue.

So far it seems to be working like a champ. With minimal modifications you can watch for any event you need to perform special actions. Don't go crazy but have fun.

Thursday, August 30, 2012

Common programmer interaction mistakes

Having worked at a number of companies I see the same programmer interaction mistakes made over and over. Maybe if they are brought into the light they can be avoided at your company.

Thinking something is too hard to code

QA, a client, support or any other person who uses the software runs into an issue. They feel like it would be impossible to implement so they never ask. So many times it turns out it is far from impossible and a lot of times it is under 50 lines of code.

Many times you will hear about missing functionality accidentally. Maybe you overhear a hallway conversation or someone in a cube close to you says "I hate this area, why does this button not have a hot-key?" There are a lot of questions that never get asked of the correct person.

The job of our medical coding team is to enter a lot of data for medical insurance claims. I had the chance to sit down and ask them what they wanted to change in the software. One of the big issues was entering decimal places for ICD-9 codes. They said software they used at other companies did not require them to enter the decimal point. Made sense to me so I changed the code to not require the decimal point but to also work if you typed it. This way the data entry did not appear to change to those who are accustomed to typing the decimal place but allowed those who did not want to type it the freedom to avoid it.

I told the project manager I was able to implement this feature and they went off on me. Before I even got to explain how it worked they told me I was breaking the software for everyone else. They had been telling people "No" for years on this request. I screwed it all up. Once they got done with their rant I explained how it worked then the calmed down and said everyone would love it. I went through the same scenario with QA and other staff members, tell them, rant, explain, smiles. It was so ingrained in their minds that this was impossible to do without destroying existing users that we could not do it. There have been many requests for this feature at our user group meetings and via the support ticket system. Of course I did not know about that, I was just told by a user how much easier it would be for them so I implemented it.

Not informing you of repetitive tasks

Copy / paste is available in some areas of the program but not others. Ask if it can be implemented everywhere. If you do a lot of copy / paste maybe you need the program to auto-fill values or if you are doing the paste into another program where you find yourself reformatting or deleting a lot of the pasted data find out if export functionality can be added. 

If it is repetitive and boring then the computer should be doing it for you. Nearly every time I have been asked to do someone else's job while they are on vacation I have found ways to automate the process. In one case a guy I worked with manipulated a Lotus 123 spreadsheet everyday. He was on paternity leave when his son was born. I was a programmer but I was asked to deal with his work too. For some reason I did not find an extra 8 hours in each day he was gone for me to do his job but I did automate it with some Clipper code to run in about 10 minutes time. He came back and found a new job within the company. Did not want you to think I am proposing the use of robots to take over the jobs of new fathers.

Not asking for a feature because only a few need it and they don't want to affect everyone.

The wonderful thing about computers is the availability of settings. Of course we don't all like the same defaults, color schemes, keyboard mappings etc. That is why programs have options screens to configure it to your liking. You need a large font, here you go. Hate the color red, use blue instead.

The other great things about computers is they take care of the boring stuff. Have an Excel spreadsheet you do the same to every day? Automate it using macros! Have a spreadsheet you need to export in CSV format once a week to import into your software? Find out if there is import directly from XLS instead. We do this using Apache POI for our Java code.

Thinking something is easy to code when it has huge system impact

Hopefully this is discovered during sprint planing. At times what seems a tiny feature can impact nearly every table and index in the database. Yes this is the opposite of my first point. Why there is so little middle ground between what a user thinks it will take to do something and what a programmer knows it will take is a big life mystery.

The area to watch out for is always saying "No" to big impact items. If you are doing a 2 month release cycle and something requires 5 months and it will really help the clients then you need to break it into smaller pieces or split a person off with development time to complete the project. You can't just ignore everything that does not fit into a neat little schedule. If you do your program will grow with little incremental fixes but will not GROW with new functionality. Other companies will come along with the missing pieces and take your business away.

Please ask, all the developer can say is "No"

First off your end users, QA staff or anyone who uses the software should never be afraid to ask for a feature. Yes, it might have to make it through the proper channels to be assigned to a release but really the worst that can happen is you are given "No" as the answer. I have seen some many really useful features blocked by the wrong people. People who assume it is impossible or it will break how existing users operate. Unasked questions are rarely answered.

It could be the full solution can not happen right away but it can be partially implemented along with another feature. This happens a lot. If I know a feature is coming in the future I can plan they way I am coding an feature now to accommodate what you need in the future. You never know, it might just come along for free due to some other code I was refactoring. For some reason places find it better to hide all future work from the programmers. Not sure why everything being a big surprise makes them think things will go smoother. I can handle knowing that a feature is for two releases out. If I know it is coming I can make sure any code I am writing now is flexible enough to handle the requests later in the pipeline.

How programmers can help

As a programmer it is our job to do our best not to break existing code. At times we have to write migration routines. We may have to allow the program to run both the old and new way. Settings will be added with the default to the way it has always been. Of course there are times with the old does not mesh with the new. Clients will complain, probably for a few weeks, then they will get used to the new more powerful way. Change just to change is not good, change with clear benefits will pay off.

Don't be dismissive with your end users. Sure, they are going to ask for really weird things that make no sense. Some of it will seem so easy to them they don't understand why you tell them it will take 10 months to code due to current code or database layout. Don't roll your eyes and them and get all technical on why it will be a bear to write. Explain that your initial thoughts point to this being a rather involved process. If they press for why you feel that way give them enough technical details so they can start to understand the complexities.

There are times you are going to mentally block a real solution and even you will think something is a 15 hour project. Later at home when you mind is a bit clearer because you are blasting pixels in a FPS you will hit a 12 minute solution. That can't happen if you did not know the problem even existed. Be open to suggestions always.

Try to find the time to sit and watch the people who actually use your software. It can be in house users or an actual client site visit. They don't always know that they are doing it the hard way. They might not realize there is a hot-key or a "Yes to All" option or another entry screen with just the data they need. Maybe they have never used the export or import functionality. 

It really is not us against them. It is us and them getting the computer to make our lives easier. The computer has no feelings so always make it the "bad guy". Take all the suggestions: good, bad, ugly, freaking weird and keep a physical and mental list of them. Over time you will knock them off here and there making everyone happy. I keep a tabbed text editor open always. I have a tab for each project, one for general notes and one for each platform I work on open always. I end up adding and deleting from my to do list all the time. When people stop by my cube to talk to me I add notes as needed. Too easy to forget little ah-ha moments and I don't want to miss out on anything that will make the software better.

Don't be afraid to fail. There are times I pull a task off the wish list, work on it for a few hours and stop saying to myself "well, I guess I don't have a solution to that". No harm, no foul. Maybe later I will come up with a solution based on my failures. Other times I look at something I typed in a number of months back and a quick solutions hits me, I try it and have success in 15 minutes of coding. That is one of the best coding feelings you will ever have. 

Sometimes I am asking Google about a current issue and part of a post will have a new direction to take on a seemingly unrelated issue. I might cut and paste that into my notes or I might have the time to tackle it right away. I have a lot of code snippets laying about that I have not used yet but am pretty sure I can use in the future.

Monday, August 27, 2012

Experimenting with HTML5 Canvas and JavaScript

I keep hearing about HTML5 especially in the mobile realm so this weekend I decided to see what I could make the canvas do using JavaScript. I have already written the new schedule viewer in Objective C on iOS, Java on Android and Java on the desktop so what the heck.

First attempt was grabbing some sample code of the web and tweaking it until I understood the basics of HTML interaction with JavaScript and basic paint commands for the canvas. I was doing this all via Eclipse and Chrome. I tried to get all the proper plug-ins installed for Eclipse but was not having much luck. I found WebStorm from IntelliJ  and installed that then things became much easier. I could actually put in break points and debug my code. If the code flat out did not run then the basic inspector in Chrome gave me the information I needed to track down those issues.

Again it has been very handy having a multiple monitor setup at home. I can have plenty of space to run WebStorm, NotePad++ etc. on main monitor and Chrome on the second screen where I can test the running application. My second monitor was a free, not super high resolution but still darn handy. Get one if you don't already have one, they are a programming life saver.

Currently I have the following working on the canvas:
Paint time margin (with various gradients)
Paint column headers
Paint grid lines
Paint dead areas outside of grid
Hold down middle mouse button and scroll around in grid

Various "objects" are set up, same objects as in the other implementations. I learned how to get the canvas to resize to fill the screen as you resize the browser. Mouse interactions including up, down, move and exit are in place. I am sure I am still doing various things incorrectly or the hard way but the code appears to be pretty clean and the paint codes runs nice and fast.

JavaScript is very close to Java for general syntax making it pretty easy to adjust to coding in it. You don't have strict variable type checking, arrays and maps have a different syntax but are really easy to use, variable scope is a bit lacking as are name spaces. Most of the code conversion was very straightforward. I can really see where it would be very handy to have a single code base for all platforms from mobile to desktop to OS of choice. Straight Java covers the OS of choice side but does not handle mobile. 

I don't see any painting limitations and the canvas 2D API is feature rich and very fast at painting. I need to chuck the code over on my server and see how it runs on the tablet when I get a little farther along. I also need to tie in the touch events to match the mouse events which should be very easy to do.

Where is will get interesting is in all the user interactions. On the PC you have click, double click, left / right / middle button processing potentials. On a touch device you have tap, double tap and long press. There are times you have to get really creative to handle user interactions. Normally on a touch device a long press will bring up a menu and double tap does a default action (which should also appear in the menu). On a PC a right click shows the menu and double left click is default action.

Still more to learn on the HTML5 / JavaScript side but I am very happy with how much I was able to get done in a few hours this weekend. The web is full of helpful examples and I have dealt with enough programming languages, SDKs and 2D APIs that I was quickly able to get it painting what I wanted.

Tuesday, August 21, 2012

You can't do that!

My job this week was to sit in with our medical coders to find out how we could make their life easier. One of the items mentioned by many of them was the requirement to type in the full ICD-9 code including the decimal point. Other software does not require this as the decimal point always occurs at position 3 according to them. If other software does it then it must not be too hard right?

If fact our FoxPro based product does not require you to type the decimal place. As we convert people from that product to the new Java / Cloud based product this has been a sticking point with them and for good reason. Your data entry staff wants to type the least number of keys possible.

Being a non-tainted innocent comes in handy when programming. I had no background on this issue. I implemented and tested the code in a hour or so. We are using a JIDE shrinkable / searchable combobox table to handle the data entry for this field. As you type the visible content of the table shrinks until it becomes the one matching code. I updated the shrinkable and searchable code to handle everything with and without the decimal point. I also found E codes have the decimal point at the 4th position instead of the 3rd and S codes don't have a decimal point at all. Code a couple of IF statements and those rules work as well. Put in a boolean so you only set this special processing when you are on a diagnosis field and I am done.

I begin to tell people I fixed the issues and they start to have fits! You are going to break all the old clients! I have told everyone you can't have that! The decimal point is right on the numeric keypad, they can type it! Whoa there, I did not break anything. You can still type the decimal point like before, if you skip typing it I do the search with it in the proper place. I handle the edge cases.

People were saying NO NO NO because they only saw one side of the solution. They hit the "it will break others" point and stopped. I had no intention of breaking existing user's data entry habits, never ever considered that a viable option. When programmers are not involved in decisions then this sort of thing will happen. They don't ask the programmer because they have already determined it is too hard or impossible. They will then turn around and require you do something that is nearly impossible that they feel is super easy. Your company needs to have a good feature request vetting process in place. It never hurts to ask but is sure can hurt to not ask.

Everyone has calmed down at this point. They really are happy this feature is in place. Our medical coders are going to be really happy when the new release comes their way in a few weeks. QA will have to get it a solid beating before it is released but the testing is pretty straight forward.

I am ready to move on to the next seemingly impossible issue.