Google+ Badge

Tuesday, September 27, 2011

Converting a phone app to Android tablets and the iPad

Just as I thought I was winding down my Android and iPhone development the Doctors tell us they have bought iPads and Android Tablets to use to enter all the data. Can't blame them as it is much easier to enter data on a tablet. The problem is we were going to target those devices on the next release. Time to quickly switch gears.

The app ran fine on the Xoom but the home screen needed to scale better. I searched the web and found new graphics for that area. With more room using larger fonts also seemed the way to go so I tweaked a few other XML files. I ended up creating a new values-xlarge directory under the res directory to hold a styles.xml file for the tablet. I find the way Android handles this to be super easy. I had to go back into a few of my other XML files to make sure they were using the named styles but that was all. I only have a few files in my layout-xlarge and layout-xlarge-land directories to handle all the changes I wanted to make on the Android Tablet.

Android does handle your app getting kicked out out memory in a way that screwed with our app. We have some global static data (I know wrist slap in order) but I need it for the SQLite database and some other login credentials. When you get booted from memory the OS tries to run your onCreate method of the visible view again. For most apps this would be great, you just pretend you started fresh and go. But with the global variables this is not so fun. I added enough checks that I don't [Force Close] any more but tell the user that the session has expired and they need to login in again. I kick them back to the login screen to get going with a fresh database and session variables.

Initially testing this case was a royal pain. You needed to leave your phone on overnight or run so many apps that it got kicked out of memory. Of course that is stupid and a few internet searches pointed me in the right direction. Fire up the emulator, run your app, use "adb shell" from the command line then "ps" then "kill #id" of your process. This will cause same sequence of events to occur. I brought up each possible activity / view and did that over and over until they all exiting clean to the login screen. You can't do this when running on a device but you can use the DDMS view in Eclipse and hit the red [stop] button to achieve the same results.

Once you start running on a real device, especially a dual core tablet, you hate to go back to the emulator. Of course QA came and took the tablet a few days after I had it in my hot little hands so I am still missing it. So much nicer to type on it and code changes are sent over to it and are up and running in a blink of an eye.

Now for my iPad experience. You can set up a universal binary in Xcode. Once you do that it will automatically switch you to the latest version of iOS as your target which is not a good thing. I wanted to target 3.0x as the minimum iOS version. Since Xcode is smarter than me things quit working on my iTouch until I figured out what it did. Simple enough to change that back.

Initial runs on the iPad looked like initial Android tablet runs. Most things looked pretty good as I was using list views and text editors. The home screen looked crappy though. I was able to use my @2x images for the retina display on the iPad. I used the stretchableImageWIhtLeftCapWidth to simulate the nine-patch image I was using for the shelves on the Android.

topShelf = [[UIImageView alloc] initWithImage:[shelf stretchableImageWithLeftCapWidth:25 topCapHeight:0]];

Worked like a charm and was much easier than I assumed it would be. I had to put in manual positioning code for each of the icons on the shelves for the iPad but there are only 6 images so that was easy enough.

I am adjusting for the height of the status bar in my code too. On the iPhone the status bar height is different between portrait and landscape but it is one height on the iPad. I put code in place to handle those special situations and everything looks pretty darn nice.

Since I have more title bar room I wanted to show the practice name on the home screen. Of course that changed the "back" button on any screen that launched from the home screen which is not what I wanted. Turns out you can do this:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {

    self.navigationItem.title = [NSString stringWithFormat:@"Home - %@", [RESTCaller practiceName]];
    UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStylePlain target:nil action:nil] autorelease];
    [self.navigationItem setBackBarButtonItem:backButton];

That code allows you to set the title text to one thing but the back button used by all other areas to something else. Not the way my mind thinks but I understand the logic behind it now that it is in place.

I want to increase the font size on various screen on the iPad. Since there is no real layout manager for iOS, everything is hard coded for widths / heights in the XIB file, this is a royal pain. You can either do secondary XIB files where you have to tie everything exactly back to the code via drag and drop or you can try and tweak things in code playing with bounds and what not. Both are sorry excuses for layout editing. I have made slow progress in this area but find the amount of work involved to be stupid.

The iPad cannot use the same call to show the picture gallery as the iPhone. I had to update the code to make the new call to show a pop-up image picker instead of a full screen gallery picker. I hope that is the only API I am using that they changed on me. Rough one to find, good thing we have QA to beat on it.

UIActivitySheets don't exactly work the same on the iPad either. They show up nice and centered but if you rotate the device while you are displaying one it will not stay centered. It stays relative to its original position. Looks ugly but this will be a really rare case so I did not fix it. There are some suggestions on the web as to how to fix it but nothing worked for me. The only thing left to consider is killing the sheet when you get a rotation notice and recreating it so it shows up in new orientation centered again. Of course if you do that really quickly you will have a new set of issues. Not worth it at this point. I see Apple cheated in this respect. Long tap a link on a web page. It pops up a menu. Rotate the screen. The Screen will not rotate until you dismiss the menu. Not what I would call a particularly user friendly way of doing things.

Camera support on iOS devices is totally hit or miss. If you want to determine if a camera is there you need to use iOS 3.2 and above calls. Seems Apple is not very forward thinking on these things and a lot of stuff gets added in later releases but I can't trust a user to be up to date. Instead I am using a call to get the machine name and basing the availability of a camera off of that. Crappy way to do things but it is working for me so far. I know iPad v1 does not have a camera and you have to be up to iPod (the iTouch) version 4 before you have a camera. The simulator never has a camera which sucks. On the Android side it simulates the camera by showing interface then returning a stock image. I had to test camera usage on an actual iOS device and I have to make sure it has a camera otherwise you get a nice crash. I don't even want to show the [Take picture with Camera] button in the UI if you don't have one.

Which brings me to the another WTF? for Apple. Why are Action Sheets index based? If I remove a button from my Action Sheet it shifts the index of all the buttons below that. Hard to write generic code and you always have to edit two places for each action sheet change you make - once where you create the buttons on once where you respond to their presses. Each button should call its own method or at least you should be able to assign tags to them so you can have one case statement. Honestly assigning tags to UI items seems pretty stinking crappy too. I do it where I can to keep track of things but it is not the most object oriented way of programming.

Some of my buttons had the dreaded "..." on them depending on what I ran it on. No device fragmentation here boys, move along. They were working find on the iPad 2 and both iTouch devices but not on the iPad 1 or an iPhone with an older version of iOS. I had to shorten the text on all devices to make sure it fits.

I have no idea if the Doctors will keep their phones up to date. At this point - pre iOS 5 - there are not OTA updates. If a Doctor never connects his iOS device back to a PC running iTunes he will have no idea there is an update out there. Will be interesting to see what iOS versions we have connecting once we roll this thing out into the wild. I have tried to test on as many iOS flavors as possible and each time I seem to find a new issue.

One other big area I can into was the 1 meg blob limit of SQLite. We are taking pictures with the built in cameras and they can easily be over 1 meg on an Android. The lackluster camera on the iPad and the iTouch don't get you into trouble but an iPhone can. I use JPEG compression to shrink the image down as needed to avoid SQLite issues. It is a shame the iPad camera is so limiting in resolution. It is an unusable solution for our doctors, the images of sheets of medical paperwork are not readable with that camera. We also allow you to choose images from the device gallery which could easily be from another device and over the 1 meg limit.

Overall it was not very difficult to get a universal app running on either the Android or iOS platforms. We are not taking full advantage of the tablet form factor but at least we are not just doing a 2X version of our iPhone app, the images scale up nicely without being blurry, you get to utilize the extra space of the device and things look native in general. 

QA is doing final testing then it will be off to the beta clients. It will be really interesting to get their feedback. Now I just need a little time to destress and I get ready to head back into Java + Swing + MigCalendar land to fix some issues in our appointment application.

Wednesday, September 14, 2011

Which way is up?

Do you ever have days where you can't even begin to tell which way is up? I have been having that feeling for the past week at least.

I am winding down the Android and iPhone development so it is at least ready to go to beta. We have a doctor that is ready to test it. We thought he was going to do it on phones and 7" tablets but he bought 10" tablets instead. I needed to add an xlarge portrait and landscape version of the home screen to the layout directory. Not a big deal but the button images need to be 256x256 to not look stupid small on the screen. My original images are 128x128 and the phone version I use 100x100. Any time you scale up things look crappy but I don't have time right now to find new base images or to totally pretty up the ones I have. I ran the sharpen tool in Paint.NET so they look acceptable.

QA has not had enough time to look it all over either. The main QA person was hit by a car while riding her bike to work. Bike is total but she is doing OK and is now back at work but under the loopy state of pain meds due to a fractured hip. To toss in irony the driver of the car is also a cyclist who has been hit by a car. Pay it forward revenge style it appears.

I think the app is pretty solid as I have run it through its paces a number of times. There are only so many screens and so many data types meaning a lot of the code is hit over and over as you create a case. I installed it a Xoom today and it ran perfectly. I have run it in the emulator but not on the actual device. The big worry is connectivity. If it drops in the middle of some areas it could be bad. Something you think about from a desktop but generally things work but on a phone walking through a hospital could cause the connection to drop easily.

I have researched the universal iPhone / iPad build setup for Xcode and I really want to take that route before we ship. Currently the iPad would just show a 2X iPhone version and I think that would be crappy. It appears Apple is using something similar to Android where you can name your XIB files with a ~ and have an iPad layout without code changes. You do have to tie all the controls to the extra XIB file but that should not be too bad. I will need better resolution images here too. Only the home screen with the buttons that launch you off to other areas should be affected but since I have not tried doing anything native iPad I would guess there are some other gotchas.

I am working on our scheduler written in Java using MigCalendar while I await QA and beta feedback on the mobile side. I have never used MigCalendar before so I have to learn those controls first. It has been a tough row to hoe. The MigCalendar API is not straight forward. Lots of parameters to lots of methods and it is not taking advantage of generics and enumerations as much as it could. The documentation is sparse and on-line help is limited. It seems to be very powerful but not super easy to understand. I have some of the requested enhancements in place I need like a tree control going more than 2 levels deep and multi-line header control for those instances. I now understand why our code was artificially limiting things to this depth as it had categories under categories that are hidden from the user as we filter 3 ways (ugly GUI here) - one from a tab, one from a combobox and one from the tree control. I need to clean all of this up without breaking how existing people use it.

I started with a test application just to learn the basics of the calendar controls. Once I got the header doing what I wanted I moved into our real code and started stripping things out and redoing what is created for the CategoryDepository which happens to be a singleton but not in a good way. This lead me to figure out why the old code that was executed every time any little thing happened in the UI did what it did. Of course nearly everything is broken now. I may have to abandon my changes due to the next item on the list.

Our C# developer has left the building but we need updates the the C# appointment scheduler. I know C# too having written a number of utilities in it and doing a conversion of a real-time stock market program from Java to C# a number of years back. Nothing like doing Java + Swing, Java + Android SDK, Objective C + iOS SDK and C# + WinForms at the same time.

There are 54 open issues on the C# scheduler and customers want them now. I have to get a handle on the code first. Initial glance shows a strong preference to cut and paste versus make a method, lack of any real comments and hard coded SQL strings that repeat every column name in every command instead of a nice collection of column names and the commands being built. You have to search a lot of code if you need to add a new column to a table and make sure everything works around it as the code stands. I can look at the code but not build and run it as it uses a couple of third party control packages and we need to transfer the developer license from the departed developers machine to mine once we sort them all out. He was not much on source control or documenting what he did so it has been a trial by fire.

I will be in another situation where I am using third party controls I don't have experience with just like I am doing with MigCalendar under Java. Mind set switching between Java and C# has been pretty easy in the past. There are some really nice things in C# and some annoyances. Visual Studio is a bit lacking compared to IntelliJ and Eclipse but is generally better than Xcode.

Yep another IDE to use. The Android side is Eclipse, Java + Swing is IntelliJ, Objective C is Xcode and now I get to use Visual Studio too! Different hot keys abound. I can easily be in all four of them in the same day with 3 running on a single machine. Keeps food on the table and clothes on the kids but my mind is turning to mush as keeping things straight during the context switches of the day can really wear you out. Nothing ever seems to be totally done and the list of open tabs I have in PSPad keeps growing. I have a tab with project notes for each item I am working on to keep track of what is left to do and my random thoughts on areas that could be improved. I jot stupid stuff on paper too during the day but try to keep a digital version of my thoughts so I don't forget things I need to revisit when I am in the code or to keep track of what is implemented on the Android that I have not ported to the iPhone or what has not gone in the opposite direction.