Latest Entries »

A colleague of mine recently had a problem in an AIR application where the styles got all messed up when a user had SWIFT KEY installed. Seeing as it’s a hugely popular app on the Google Play Store it wasn’t something she could just ignore. The problem is that AIR doesn’t give you a way to detect or change the keyboard, and after 2 weeks of searching she’d given up on trying to find a native implementation.

It turns out this is a relatively trivial thing to do in native java. By getting the INPUT_METHOD_SERVICE we can use the InputMethodManager class to determine what keyboard is currently being used, for example:


private String getKeyboardType(){
InputMethodManager imm = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
List mInputMethodProperties = imm.getEnabledInputMethodList();
final int n = mInputMethodProperties.size();
for (int i = 0; i < n; i++) {
InputMethodInfo imeInfo = mInputMethodProperties.get(i);
if (imeInfo.getId().equals(Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD))) {
return imeInfo.getId();
}
}
return "";
}

The above method returns the current keyboard string definition. In the case of my colleague’s problem, parsing that string for the word “swiftkey” allowed her to determine if swift key was being used as the current keyboard.

While Android prevents you from switching the keyboard programatically, it does give you a way to launch the keyboard switcher. This is the built in dialog used in the setting app to set the keyboard. You don’t need to go to settings, you can just launch it from your app.


private boolean showInputMethodPicker() {
InputMethodManager imeManager = (InputMethodManager) getApplicationContext().getSystemService(INPUT_METHOD_SERVICE);
if (imeManager != null) {
imeManager.showInputMethodPicker();
return true;
}
return false;
}

Hope this saves you some time.

Building a Scrum Board

The project I’m currently working on gave us an opportunity we rarely get – a room to ourselves to setup any way we liked. And as we’re a scrum team, the first thing we needed was our Scrum board. At the beginning of the project we had a few different styles. As a former scrum master, I’d found that sticking cards on a white board worked well, while the scrum master on this project came from a team that used magnetic strips instead of cards, also on a white board. But when we started the project, our white boards hadn’t been delivered yet. We spent the first 4 days of Sprint 1 staring at magnetic strips on the floor, while we were waiting for our boards to be delivered. By day 5, following a minor temper tantrum over not being able to visualize what was going on, I got in my car and raced to the stationery shop to buy string and some Prestik and put up a make shift scrum board until our white boards arrived. Well, we’re in Sprint 6 now, the white boards have arrived, and we’re still using the string based system. It’s given us the functionality to adapt and change the board as our needs and process evolve.

Here’s our basic template for our scrum board:

ScrumBoard - Basic

The lines are created by using prestik to stick the string onto the wall. All stories are written on index cards and stuck on the wall. We write our acceptance criteria on the back of the cards. As we need, we add stories onto the product backlog, and prioritize them. The stories at the top of the board are most important, from left to right. During sprint planning, we break them down into smaller stories where necessary, and move those into the Sprint Backlog column.

When a story gets worked on, it moves into a swim lane in the Active Stories column. The developers then add their tasks for that story using stickies (Post-It notes) in the Story Tasks columns for that swim lane. When the task is being worked on, it is moved into it’s In Progress column, and again, when the task is complete, we move it into the Completed Tasks box on the swim lane. Once all the task stickies are in the Completed Tasks column, it’s ready for testing, and we remove all the stickies for that story, and move the story card into the Testing column. This does not mean write the unit tests, they should be there already. It just means that the Tester in our team starts the functional testing, and only he can move a story to done. If there are issues/bugs, he moves the card back into an active swim lane, and adds a sticky per bug, and the normal process continues. Once he’s happy, he moves the card to done.

This process is obviously up to you, and should suit the way your team wants to work. The beauty of using string on a wall is that you can change and adapt it at any time, and you can use the whole wall, and are not limited by the size of your white board.

We’ve adapted it ourselves as we’ve gone along. For instance, in our Product backlog, we set up different columns for each area of the system so that we could manage the priorities per area (you could use the same approach if you had multiple projects). We then started reflecting our release planning by separating the product backlog into future sprints, and at the moment, our board looks more like this:

If there’s one thing you take from reading this, I hope it’s that old school is still the king. To run an effective, productive scrum team, you don’t need expensive digital systems, in fact, I advise against them. A good scrum master can easily mirror whats on the board in an excel sheet, and manage stakeholders by constantly distributing it. Or even better, get your product owners to manage the backlog on the board itself.

So yesterday I applied the windows update to install IE9, and discovered that my ajax calls to update a grid stopped working. Chrome & Firefox gave the expected results (i.e. my grid showed changes), but in IE9 seemed to display whatever the first load was.

IE9, it turns out, makes 2 different kinds of requests, conditional and unconditional requests (for more checkout http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx). Unconditional requests occur when the browser doesn’t have a cached copy, and so the browser makes a new request to the server, and using details in the response header, determines how to cache the document. Conditional requests occur when a cached copy is available. It first evaluates whether the document is still fresh, and if so, serves the cached copy of the document.

Many people seem to counter this by passing a date time stamp string as a URL parameter, making each request unique, and thus the browser is always making an unconditional request, and always getting a new copy. This just seems dirty, as you’re passing up a parameter thats not required. It’s also quite error prone, as if you forget to add the parameter you’ll run into caching problems that often aren’t easy to spot.

Luckily ASP.NET MVC makes it relatively straight forward to control the “Cache-Control” section of the HTTP 200 response header field, which is what IE9 uses to determine its caching strategy.

A normal MVC response header looks something like this:

By default, MVC responses set the Cache-Control setting to private, which the HTTP specification (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1) describes as:

Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache. This allows an origin server to state that the specified parts of theresponse are intended for only one user and are not a valid response for requests by other users. A private (non-shared) cache MAY cache the response.

The result of this is that IE9 will cache the page in the current user’s private store, and will conditionally serve the cached copy until it reaches it’s default expiry time.

To change this setting, we simply add an attribute to our MVC controller.

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class CacheTestController : Controller

We’ve set “no-store” to true (meaning don’t cache), and the “duration” to 0 (so it immediately expires). This will ensure that every subsequent request for this page will result in a new trip to the server, and a fresh copy being served.

A much neater solution, that requires no changes to our URL’s, or the parameters passed to it.