Nov 06

LoanShark_1

A while back I released a new, completely-rewritten version of LoanShark. The current version is 2.0.6 which contains a number of

bugfixes, and I consider it to be quite stable. I think writing this version took considerably more effort than the first one, or maybe I have just forgotten how much effort went into the first attempt.

There were problems with database migration code from the previous version. I’ve done away with some tables altogether to make things simpler, which necessitated writing quite a bit of migration code. Migration is both engaging and frustrating at the same time. On one side there’s the need to evaluate the old and new database structures exactly and trying to figure out the simplest way to transfer old data to the new format. On the other side there’s no way around writing migration code unless you want to make your app crash on your users’ faces when they update to the latest version.

I thought I had ironed out the potential migration issues before releasing the first update, but there were several bug reports from users. I guess most of the users don’t bother to send an error report when an app crashes on startup; they’ll just uninstall it and be on their merry way. Fortunately it also seems that they don’t even bother to write those nasty 1-star reviews either.

During last week I was contacted by two users who had crashing problems, one of which wasn’t related to database migration. I’m very thankful for all feedback, even if it’s crash reports. It gives me the extra kick in the backside that keeps me motivated to continue development.

Sep 21

To force the garbage collector to run from adb shell, first find out the target process’ id (using e.g. ps), and then execute this in the shell (as root):

kill -10 <pid>

You should see GC_EXPLICIT in logcat:

I/dalvikvm﹕ threadid=3: reacting to signal 10
I/dalvikvm﹕ SIGUSR1 forcing GC (no HPROF)
D/dalvikvm﹕ GC_EXPLICIT freed 1K, 9% free 9250K/10112K, paused 12ms+2ms, total 60ms

Before Android 2.3, the afore would also dump the heap. On modern platforms (since Android 3.0), you can use the following, which doesn’t require root:

am dumpheap <pid> <output_file>
Apr 07

In September last year, I was excited about Samsung’s announcement of the Galaxy Tab 7.7. It had a Super AMOLED HD display at 1280×800 resolution without any of the crappy PenTile matrix faking. As is customary with Samsung, months passed by without the product actually making it onto store shelves. When it finally was available, there were a lot of rumors about a fabulous new iPad with a 2048×1536 resolution screen.

Due to the annoying patent war between Apple and Samsung, I had thought about not buying another iOS device before sense would prevail and the two companies would stop with their lawsuits and counter-lawsuits. Then came the new iPad, and I knew I had no hope resisting buying one. The only thing I wasn’t sure of was if I was going to buy it as soon as possible, or at some later date. As it turned out, I was a happy owner of a new iPad on the launch day.

It’s not that I had a pressing need for an iPad. It’s that the new display was just too gorgeous to pass by. And believe you me, it really does shine. But the screen is not the only positive thing about the device. I never owned an iPad 2 (I only once quickly tried out one in a shop), so I can’t make any comparisons with that, but I did buy the first generation device when it was released. The new iPad is quite a bit more joyous to use, especially because of the four times larger memory capacity. When browsing web pages, there’s no longer that annoying checkerboard effect that plagued the first generation device (and the iPad 2 as well to some extent; this was the reason, incidentally, why I didn’t upgrade back then).

Originally I had contemplated buying the new MacBook Pro when it comes out in early summer. I already have the early 2008 model, which is quite usable for my purposes, but you can’t beat the feeling of using a brand new, expensive, and exceptionally well operating machine. On the other hand, I’ve by now gotten used to the higher DPI displays, and it would therefore be probably quite useless to buy a new laptop with the same 1400×900 resolution. There will most likely be a 1680×1050 screen option for some extra cash, but that would still be nowhere near the high DPI of the new iPad. (Yes, I’m a spoiled brat now.) I could get the Air (and save quite a bit of money as well), but I don’t know if I’d be able to give up the extra power that a Pro provides.

Having said that, after using the new iPad for a couple of weeks, I increasingly feel that I could be able to skip the purchase of a new MacBook Pro/Air altogether. The iPad is just that good. I’m still learning he ropes with the typing experience, but it’s much better than I thought it would be. The autocorrect feature is a blast, although by no means perfect. One thing I’ve noticed, though: when typing on the iPad, I keep on watching the keyboard all the time, instead of looking at the text I’m producing. This is the complete opposite of what I do when typing on a real keyboard. It must be because of the lack of physical keys; I have no felling of which keys my fingers are on, so I need to constantly watch over them. The speed of typing (in this semi-awkward position of lying in bed) is actually surprisingly good. I must later assess my typing speed when sitting properly at a table.

I need my PC for playing games (Civilization 5 mostly), but it seems that at the moment I really don’t have a pressing need for a Mac laptop, at least not a new one. I do have, in addition to the aforementioned MBP, a Mac mini 2011 (2.5GHz), which I use sporadically, so I’m pretty well covered if I later want to do some iOS coding. Other than that, most of my time on a computer is nowadays spent on the iPad. I don’t know if there is going back. A laptop feels, by now, somehow old-fashioned. Physical keyboard has of course no parallel, but since I can do pretty much everything on this wonder slate, I ponder if I can now permanently move on to the post-PC era that Steve Jobs talked about when the first generation iPad was released.

By the way, when I purchased the iPad, I also grabbed the iPad Smart Cover (navy blue leather). It was a bit under 70 euros (a ridiculously high price), but at least it works quite well for what it is. I could have opted for a polycarbonate version, but they didn’t have one in my color, so I had to cough up 30 euros more (I can’t believe I just said that).

Dec 26

Last week I bought one of the new Galaxy Nexus phones that had just become available here in Finland. After using it for a while I realized that the screen sported, for some reason, a yellow tint. Having used my Galaxy S for about 18 months now, the difference was quite a stark one, even to my eyes. I snapped a photo of the Nexus next to my Galaxy S, both at full brightness.

I find it hard to believe that Super AMOLED technology would have gotten worse in the last year and a half. Granted, the resolution is significantly larger (480×800 vs 720×1280), but the difference in quality (pixel density notwithstanding) was too tremendous for me to bear.

I posted the above photo to a couple of websites I frequent, and sought for opinions. I had, by that time, already arranged for my Nexus to be RMA’d, so what I was looking for were reassurances that I would, with high probability, get a better device as replacement. I didn’t get many replies, but the ones I did indicated that I might in fact have had a defective screen. I then proceeded to pack the device up and sent it back to the store.

Since it’s Christmas, it’ll take a few days more to make the trip to the store (which is in Sweden), and for the new unit to be shipped back to me. I could, in fact, pick another device from my local store, compare the screens, and then sell off the one I like less. Nexus being sold for 650 euros at my local store, this plan might prove too expensive in the end.

I have the tracking code for the package I sent back to the store, so I can start asking questions about the replacement (in case they don’t contact me first) once they receive the shipment.

In all honesty, I don’t have high hopes for the screen of the replacement unit either. I’ve got the impression that the Nexus screen is supposed to be somewhat yellow, and also feature a blue tint when looking at it at an angle. Still, having used Galaxy S for 18 months I had expected something at least as good. My initial unit seemed clearly a step backwards what comes to the screen quality.

In all other respects, Galaxy Nexus didn’t disappoint. I was actually a bit uneasy when the specifications were released, because I had expected a 1.4 GHz dual-core processor paired with the Mali-400 GPU at least. That would have made it a bit better than Galaxy S II. It is obvious, however, that Samsung wants to keep the Galaxy S line as the pride and joy of the company. It doesn’t take a lot to figure out that The Galaxy S III, presumably available in April-May 2012, will blow Nexus out of the water. Nexus will probably sell about 1-2 million units in its lifetime, while Samsung is likely expecting the S3 to sell 10+ million units before the end of year.

The most important thing for me in buying the Nexus phone was vanilla Android 4.0. When I got the phone I found it difficult to put down. It wasn’t primarily about the hardware but the latest version of Android, which was truly a joy to use. Certainly it was a different feeling from using Eclair, which was my initial foray into the world of Android.

The Nexus devices are supposed to get updates from Google/Samsung (depending on build) quite soon after they are released, which, as a developer, was a major point to consider. I want to play with the latest and greatest as soon as it becomes available, instead of having to wait for months until the manufacturer releases their newest atrocity of a skin on top of the OS. There are ROMs, of course, but there’s really no beating the original, vanilla experience — to use the device just as Google intended.

Edit — My replacement unit arrived yesterday (10 Jan). It’s a different device all right (based on IMEI), but I can’t tell any difference from the unit I sent back. It seems that people who got a “flawless” screen either don’t know what they’re talking about, or just got very lucky. I think my Galaxy Nexus is just as good as it’s supposed to be. Were the screen any better, it would be a manufacturing fluke.

I’ve used the teamhacksung ICS port on my Galaxy S in the meantime, and I have to say that it rocks. Unfortunately, it has also made the woo factor of ICS wear off. When I got my Nexus replacement, it didn’t feel at all like the first time I got my hands on the device. Now it’s just the best phone I’ve ever used, although not significantly so.

Oct 20

Sometimes it’s convenient to direct the output of a command to both the screen and a file. Here’s how to do it:

command 2>&1 | tee output.log

The tee command copies stdin to stdout, and makes a copy of the input to a file. The 2>&1 part also directs the stderr output, in addition to stdout. You can use tee -a to append to the log instead of overwriting.

Jun 17

Samsung published a press release a couple of days ago, citing that the Galaxy Tab 10.1 will be released in August in the Nordic countries (including Finland). I’ve been waiting for the device to be available since it was announced at CES 2011 in January. It is released in the US this week (nationwide), and I hoped that European release would be just around the corner. But no, I still have to wait 2-3 months more in addition to the 5 months I’ve already waited. Enough is enough.

My plan was to get into Honeycomb development by the time I leave off to summer holidays (4 weeks in July), so obviously the Galaxy Tab is a bust for me in that respect. Yesterday I ordered a WiFi-only Motorola Xoom from Amazon.co.uk for 527 euros. I may switch to Galaxy Tab 10.1 once they are finally released and available in Finland (or the UK) as well, but that also depends on how satisfied I am with the Xoom, and how much money I would receive back when I would sell it.

Apparently the Honeycomb 3.1 update is not out for WiFi-only Xoom yet, but hopefully it will be released by the time I receive my device.

May 21

Last Sunday I released a new version (1.05) of LoanShark. The next morning I checked, as usual, whether anyone had had problems with the new version. Sure enough, there was one crash report waiting for me. I tried to figure the problem out before leaving off to work, but I wasn’t able to do so in the short amount of time I had available. I figured that maybe it was a single incident, and that I would later check if any error reports pour in, that would contain a better indication as to what might be the problem.

In the Android Market control panel, the link that goes to the error reports hadn’t changed for a few days (I eventually found out that it displays the number of releases with errors), so I figured there had been no new crashes and didn’t pay attention to the matter any further. As the days went by, I began a little worried about the installations not increasing at their usual rate.

I had received a report from a user to LoanShark’s own page on my site, so I figured there must be something seriously wrong. I decided to check out the error report page at the Android Market control panel, and lo behold, there were 19 error reports in total. Whew!

I think the link to the error reports page should display the total number of errors in the latest release, not the number of releases with errors. Now it just displayed the same number for five days, so I didn’t bother checking the reports behind the link at all.

The reason behind the crash was that I didn’t check for a null pointer in a section of code where the database schema is being upgraded to the latest version. If there were loans that had been returned or repaid in full, the upgrade would fail.

I’ve uploaded a new version (v1.05b) to the Android Market, which fixes the problem. Now existing users are also able to enjoy the plethora of enhancements in the latest version.

Incidentally, when loans are returned or repaid in full, they are not actually deleted from the database, but just marked as being inactive. This is because I’m planning to write a feature which would allow viewing (as read-only) the loan history. Such old loans could then be used, for example, as a template for creating new loans.

If you come up with suggestions for new features, please feel free to leave a comment!

Edit – Fixed one more bug that caused a crash when the quantity of lent/borrowed items was unset. The fix is included in the latest version, v1.05c. I found another bug, although this one is not so fatal: when sending SMS from an overdue loan’s management view, if the contact has more than one phone number set and you select a number, it tries to open the email editor instead of the SMS editor. Haven’t got yet time to fix this but it shouldn’t be a biggie.

Feb 20

So, on the 11th of February 2011 Nokia announced that they’re going to ditch Symbian and Meego in favor of the Windows Phone platform. This has sent tremors across the Finnish IT-industry which has been heavily dependent on Nokia. What this means is that potentially thousands of people working directly or indirectly on Symbian and/or Meego will be forced to find new job opportunities. Of course, the change won’t happen overnight but it is obvious that less and less money will be diverted towards Nokia’s own platforms in the coming months.

The organic growth of the Finnish outsourcing companies (which is where I work) has been heavily dependent on Nokia, and chances are Nokia’s decision will hit them hard. Nokia has decided that there will be minimal customizations to the Nokia Windows Phone devices, which means that there will be minimal amount of work to be done to customize the phones. Obviously, lots and lots of people will be moving on from Nokia projects to pastures new.

At the moment no one knows how things will proceed from here. It is certain that there will be layoffs and lots of them, since there is just not going to be enough work for everyone. This doesn’t concern just engineers, but also management, IT-support, HR-personnel and others who have worked more or less directly with Symbian and/or Meego.

For what it’s worth, I’ve been working with Symbian for six years and it certainly has taken its toll. I have no sympathy for its fate. I haven’t seen Meego so I can’t say much about it, other than what I’ve read from the press.

Obviously this is a time when one must be very alert to what the future will bring. Since Symbian is a dying breed, there’s no reason to invest in it anymore. Meego and Qt also received heavy blows with Nokia’s announcement, so their future (both immediate and long-term) look uncertain. Windows Phone is a big question mark, even with Nokia’s backing; the platform has been on the market for a few months and it has generated just a small amount of buzz.

Personally, I see two opportunities in my future: Android and iOS. Both are hot commodities at the moment, especially with Android’s rocket-like surge in popularity since its release by Google in 2008. Development on iOS is done using Objective-C, while on Android, Java is the language of choice. The most natural transition for me is of course Android, with Java being closely related to C++. Java is of course an “easier” language than C++, enabling faster pace of development, although it also has its own characteristics that have to be learned in order to be able to use the language effectively. With Android’s Native Development Kit (NDK) it is also possible to write C++ code when speed or closer access to hardware is of essential importance.

In fact, I decided to start investing in Android already last summer, when I bought the Samsung Galaxy S to replace my iPhone with a view to learning Android development. During last autumn I started to have a look at Android and did some small-scale experiments. A few weeks ago I got an idea of an application that I started to write with my then-acquired skills. It has taken a few intense weeks of my free time, I’ve learnt tremendously, and I’m proud to say that my first Market-worthy application, LoanShark, is ready.

Jun 07

Working in an office environment isn’t always going to be quiet. There are often people coming and going, with the sound of footsteps and the doors opening and closing. In addition, you’re usually able to hear at least a couple of people talking, be it work-related stuff or something else. That said, I don’t mind at all people talking about non-work-related things at work; for me it’s a sign of a healthy work atmosphere.

In this line or work, I consider it essential to have a good pair of headphones. I prefer closed headphones for two reasons. First, they keep a lot of the external sounds from reaching your ears. You don’t even have to play any music if you don’t want to – in this case they work as glorified ear protectors. Second, they insulate the noise the other way as well; they don’t let the sound spread to your surroundings. Which means that you don’t have to bother others with your music even when you play it loud. You can even occasionally listen to those horrendous 90’s party hits just to remember how terrible they were – without giving anyone a clue about it.

I currently have a pair of Sennheiser HD 212 Pro’s at work, which do an amicable job. They’re not top of the line – and not top of the price ladder either. Whenever I need to do some serious thinking, I put on the headphones and select some music with no vocals either from Di.fm or Spotify. The no vocals part is essentially important; I feel that I absolutely can’t concentrate when someone’s yapping into my ear.

As a lighter alternative, I also have Sennheiser CX-300 II’s, which I usually use with my iPod at the gym (or when vacuuming!). For the price they’re pretty good as well, and the noise insulation is not bad either. In fact, I used them as ear protectors when I was at the Australian GP this year. They had a FM transmission that I could listen to at the same time while I had my ears adequately protected from the noise of the cars (the Renaults were the noisiest, mind you).

To complete the set, I have a pair of Sennheiser (anyone recognise a pattern ?) PX-100’s which I use at home. They’re lightweight, open headphones with decent sound. I previously used them at work, but since they provide no insulation and seep out sounds when playing at louder volumes, I decided to go for the closed headphones instead.

May 23

Searching for elements in an STL container is a common task. There are several ways to accomplish this. Let’s have a look at some of them.

Suppose we have a collection of elements in an STL container. The element type is defined as a simplified phonebook entry, as follows:

struct Entry
{
    Entry( const string& n, const string& p ) : name( n ), phoneNum( p ) {}

    std::string name;
    std::string phoneNum;
};

We then push some entries into a container, e.g. a list, like follows:

std::list<Entry> phonebook;

phonebook.push_back( Entry( "James Bond", "123" ) );
phonebook.push_back( Entry( "Felix Leiter", "456" ) );
phonebook.push_back( Entry( "Vesper Lynd", "789" ) );

We’d then like to look up the phone number of a contact. We know the contact’s name, so we can search it as follows using a for loop and an iterator:

std::string searchFor = "James Bond";
std::list<Entry>::const_iterator iter = phonebook.begin();

for ( ; iter != phonebook.end(); ++iter )
{
    if ( iter->name == searchFor )
    {
        break;  // No need to look any further
    }
}

if ( iter != phonebook.end() )
{
    std::cout << "Call " << searchFor << " at " << iter->phoneNum << endl;
}

Quite simple. We could also make this into a function, and call it whenever we need to seach for a number:

string GetNumber( const std::list<Entry>& phonebook, const string& searchFor )
{
    std::list<Entry>::const_iterator iter = phonebook.begin();

    for ( ; iter != phonebook.end(); ++iter )
    {
        if ( iter->name == searchFor )
        {
            break;  // No need to look any further
        }
    }

    return iter->phoneNum;
}

There is also a more elegant way; we can write a comparison operator that returns true if the given Entry matches a specified std::string, and use it with the STL's find() algorithm. For the purposes of this example, it doesn't matter if the operator is a member operator or a global one. Here's the global version:

bool operator==( const Entry& e, const string& n )
{
    if ( e.name == n )
    {
        return true;
    }

    return false;
}

Make sure you have the parameters so that the container element type is on the left side, and the comparison argument (i.e. the third parameter to find()) is on the right side; this is what the algorithm expects.

Armed with this function, we are able to use the find() algorithm (remember to #include <algorithm>) to do our bidding:

std::string searchFor = "Vesper Lynd";

std::list<Entry>::const_iterator iter =
    std::find( phonebook.begin(), phonebook.end(), searchFor );

if ( iter != phonebook.end() )
{
    std::cout << "Call " << searchFor << " at " << iter->phoneNum << endl;
}

The find() algorithm compares each element of the specified range (between begin() and end(), as specified above) against the third argument, which happens to be the search string. Given that we now have a comparison operator taking an Entry struct and an std::string defined, the compiler calls the operator for each element in the range. The find() terminates either when the comparison returns true, or when the iterator position specified as the second argument to the algorithm is reached, i.e. phonebook.end().

You can also use find_if() with a function object as a search criterion. Function objects have also much more powerful features than mere functions, e.g. the ability to maintain state between invocations, but for this example we'll use one just as a simple comparison critetion. Let's have a look:

class CompPred : public binary_function<Entry, std::string, bool>
{
public:
    bool operator()( const Entry& e, const std::string& s ) const
    {
        if ( e.name == s )
        {
            return true;
        }

        return false;
    }
};

Here we derive a class from binary_function, and add a function call operator (operator()). The template parameters to the base class are two of the argument types (here Entry and std::string), and a return type (bool). What we're doing here is basically a template specialization of the binary_function class template. We then use the Entry and std::string types as parameters for the function call operator, akin to what we did with operator== above.

We can then do the search using a slightly modified version of the previously presented code:

std::string searchFor = "Vesper Lynd";

std::list::const_iterator iter =
    std::find_if( phonebook.begin(),
                  phonebook.end(),
                  bind2nd( CompPred(), searchFor ) );

if ( iter != phonebook.end() )
{
    std::cout << "Call " << searchFor << " at " << iter->phoneNum << endl;
}

Note the use of the find_if() algorithm. It takes as the third argument a pointer to a function or function object derived from unary_function. The bind2nd() adapter takes as parameters a function object and the search argument. We need the adapter in order to convert a binary function (taking two arguments) into a unary function (taking a single argument).

This post has droned on for quite some time, so I'll cut this short. There are loads of stuff I deliberately left unexplained here, e.g. why the function object's operator() must be declared const, function objects and function adapters, and template specializations, but I'll save those for another time, my dear imaginary readers.

preload preload preload