Rss

Archives for : android

Edit Outlook.com contacts on an Android phone

The other month the Outlook.com Android app was updated. It changed the Outlook.com app into something that you had to use (if you used Outlook) to something you want to use. Many of the bugs in the previous version (which wasn’t that good to start with) were ironed out, and it got a nice facelift.

One thing that the app does is syncs calendar and contact information with your Android phone as well. The calendar sync was 2-way: add an entry with the web interface and it will sync with the phone, and vice-versa. This is how cloud computing should work, and it’s how it works for your Google Calendar. However, one thing that was always an issue was contacts; contacts would sync from the web based interface onto your phone which was great, but you can’t add a contact to your Outlook.com contact database from your phone. It was just a one way sync.

This happened in the old version, and unfortunately still happens in the new version. However, the other day I was browsing the Microsoft Support forums to see if this is ever going to change, and found the following app: Contact Editor Free. It can edit and add Outlook.com contacts from your phone. In addition, Contact Editor Pro allows some additional features, such as creating a default (otherwise it will always ask you where you want your contact saved: on your phone, on your Google account or on your Outlook.com account.)

So, with that, I’ve pretty much got my Outlook.com account working how I want it with my Android phone. The only thing that isn’t synced in contacts is contact groups, however I am getting around this by using the grouping feature in GO SMS Pro (which can handle groups within the app rather than in the contacts app.)

Android: SQLite Database Upgrade

Note: I haven’t edited this since writing it, or fully tested the code that I present (that said, it’s heavily based on one of my apps, it’s just I’ve reduced the number of tables being made.) I will update the tutorial later on when I get a chance.

There are quite a few tutorials out on the web of how to make a SQLite database within an Android application, but not so many that deal with proper upgrading of the database.

Over time the requirements of the database within your application may change, this is almost inevitable if your application is in active development and you’re constantly adding new features. Properly upgrading the database in your app is important, because if something goes wrong your application will have unexpected behaviour (such as crashing) or you may loose all your user data and have to start over.

Version 1 of your database
If you have followed one of the numerous tutorials online on how to setup a SQLite database in your app, you most likely have some form of DatabaseHelper class that extends SQLiteOpenHelper. It may look something like this:

package com.example.sampledb;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.text.SimpleDateFormat;

public class DbHelper extends SQLiteOpenHelper
{
    private static final String DATABASE_NAME = "mysampledb";
    private static final int DATABASE_VERSION = 1;

    private static final String DATABASE_CREATE_SAMPLE_TABLE = "CREATE TABLE tblSample" +
        "(" +
        "   _id integer primary key autoincrement," +
        "   name varchar(32)" +
        ");";

    public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSS";
    public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT);

    public DbHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database)
    {
        database.execSQL(DATABASE_CREATE_SAMPLE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        // Do nothing for now
    }
}

Each time it is called, it will check to see if this database and version already exist. If the database doesn’t exist, it will create the database by calling onCreate(), and it will store the database name and version number with it. If it does exist, but the version of the current version is lower than what is defined in DATABASE_VERSION, the onUpgrade() method will be called.

Version 2 of your database
The question is, what is the best way to handle an upgrade? I had a think about the way it worked, and I decided the best way would be to loop through all the different versions and apply the required changes.

Let’s say you wanted to add a field to “tblSample” called “address”? The new statement to create the database table would look like:

CREATE TABLE tblSample
(
    _id integer primary key autoincrement,
    name varchar(32),
    address varchar(128)
);

Which you will obviously what you want to change your “DATABASE_CREATE_SAMPLE_TABLE” variable to, since you want all new creations of the database to be up to date. You also want to use the onUpgarade method(). The way I have implemented the onUpgrade method is as follows.

package com.example.sampledb;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.text.SimpleDateFormat;

public class DbHelper extends SQLiteOpenHelper
{
    private static final String DATABASE_NAME = "mysampledb";
    private static final int DATABASE_VERSION = 2;

    private static final String DATABASE_CREATE_SAMPLE_TABLE = "CREATE TABLE tblSample" +
        "(" +
        "   _id integer primary key autoincrement," +
        "   name varchar(32)," +
        "   address varchar(128)" +
        ");";

    public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSS";
    public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT);

    public DbHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database)
    {
        database.execSQL(DATABASE_CREATE_SAMPLE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        for (int i = oldVersion; i < newVersion; i++)
        {
            switch(i)
            {
                case 1:
                    db.execSQL("ALTER TABLE tblSample ADD address varchar(128)");
                    break;
            }
        }
    }
}

How will this work? Well, quite well from what I’ve found, since it will work for any upgrade… if you always use this method, it will work for upgrading from version 1 to 9, or from version 4 to 5. Basically, it will loop through all the previous versions starting at the current version.

So, if my phone is on version 1, and the app needs to upgrade to version 2, this loop will iterate one time, with the value of “i = 1.” The switch case statement should, for each version number, execute the required statements to upgrade from that version to the next. So, in this case, “case 1:” will execute the required statements to upgrade from version 1 to version 2.

Potential Problems
The biggest problem that you may face is if your “fresh” database creation statements get out of sync with all the update statements. What should always be the case is, if you start with version 1, and run all the update statements to get it to the newest version, the schema of the database that has been upgraded should match exactly the schema of the database if it were created from the newest version.

In short, the best way around it is only make small changes to your database at a time, and make sure you apply the changes to both the creation statements and the update statements such that they match. I would also suggest always using string literals in the update statements rather than refer to any variables. This would definitely be the case if you need to create a new table. It would be tempting to just refer to the DATABASE_CREATE_NAME_TABLE variable in the upgrade section, but remember that this variable should be creating the newest version of the database, and in your upgrade statement, you need to be aiming to move to the version after what is specified in the case statement. So whilst it will work at first, when you change that table, it may mess up.

A potential solution
One potential solution I have thought of that may work is to keep the create table statements the same such as they were in version 1. Then, when you create a fresh database in the onCreate method, you create all the tables as they were in version 1, you call the onUpgrade method with the variables (database, 1, DATABASE_VERSION). It would look something like the following:

package com.example.sampledb;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.text.SimpleDateFormat;

public class DbHelper extends SQLiteOpenHelper
{
    private static final String DATABASE_NAME = "mysampledb";
    private static final int DATABASE_VERSION = 2;

    private static final String DATABASE_CREATE_SAMPLE_TABLE = "CREATE TABLE tblSample" +
        "(" +
        "   _id integer primary key autoincrement," +
        "   name varchar(32)" +
        ");";

    public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSS";
    public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT);

    public DbHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database)
    {
        database.execSQL(DATABASE_CREATE_SAMPLE_TABLE);
        onUpgrade(database, 1, DATABASE_VERSION);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        for (int i = oldVersion; i < newVersion; i++)
        {
            switch(i)
            {
                case 1:
                    db.execSQL("ALTER TABLE tblSample ADD address varchar(128)");
                    break;
            }
        }
    }
}

I haven’t tried this, and I don’t think it’s the best way to go. If it does work, it would reduce the potential of a miss match between the same version if it were created fresh or upgraded, since it’s just creating the first version and upgrading it to the newest version.

The main problem with this I think is that it doesn’t force you to think about the structure of your database, and could easily turn you into a lazy programmer (like having a catch clause that doesn’t do anything.) The other problem I can see is that it’s hard to see at a glance the structure of your database in the newest version, since you will need to process all the upgrade statements to see what it really looks like.

It’s your choice. This way should work, and will pretty much eliminate any possibility of a miss match between a fresh and upgraded database, but at the same time you lose the ability to see the structure of your database, and it has the potential to make you lazy.

Virgin Mobile Usage Android App: Version 2.0 Released

feature_graphic

I’m excited to announce that I’ve finally been able to push out the update for my Virgin Mobile app that I’ve had in the works for at least 2 months. I have been really keen to get it out, but held off until after it had been tested as much as possible, to try and reduce as many bugs as possible.

I’ve listened to overall feedback from comments on the Android market. It now looks better, functions better, and, well, let’s just say it is much better than what it was. If you used my one before and didn’t like it, definitely try it again.

Changes include a new interface, new widget, billing support (view bills,) and most importantly, an improved backend that uses a database to store information. This won’t be noticeable to users at first, but over time it should be: the app should be more reliable, and display better data. The version before hand was riddled with bugs, and many of them were unavoidable due to the way that I stored the data. It got so bad that I decided the best way to fix everything up was to ditch the old system and implement an improved system.

I hope you like it, and remember, I’m encouraging those who use this app to donate to World Vision if they are considering making a donation. Donations are going to go to a lot more use there than they will going to me!

Visit the Market Page

Google Developer Day 2011

Looks like heaps of fun! I’ve registered, hopefully I get in (not all registrations do.)

Google Developer Day Sydney Website

Edit (13/10/2011): Got in. Found out yesterday, less than 24 hours after submitting my registration.

Number Search Now Available

Head over to the Android Market and grab it now!

After getting annoyed with the official White Pages app (which is nothing more than a glorified bookmark,) I decided to make a native app that takes advantages of Android in a way that a web site can’t (mainly calling contacts, navigating to their address, and adding to contacts.)

It is currently in beta, so please email me or leave a comment on this post with any issues you come across.

Number Search: White Pages-esque Android App Coming Soon

In a past blog post I mentioned that I had another Australian based Android app in the works, and I’ve made enough progress with it to announce that I plan to release it soon.

The app is called Number Search, and is basically a White Pages app that isn’t a glorified bookmark (such is the case with the current app.) I still can’t give an estimate of whet I will be able to release it, there are still more things to do, but I’ve made enough progress that I’m confident that I should be able to get it out soon!

Music Unlimited powered by Qriocity Review

For those of you who don’t know what Music Unlimited powered by Qriocity (seriously, who thought of that as a name) is, it’s a subscription based music service by Sony, with quite complicated branding. It’s PSN, it’s Sony Entertainment, no, it’s Qriocity, all at the same time. I don’t even know how to pronounce that properly, so luckily that isn’t a requirement for a text based review.

The deal is, you pay $13 (AUD) a month, and get unlimited streaming of any song in their library. It sounds like a pretty good deal on the surface, but is it really? Let’s find out.

Music Range
Well, it’s Sony, so anything Sony related is in there. That said, all the major label seem to be represented, meaning that it will have 99% of the music most people want (since, by definition, what most people want is mainstream music.) It won’t be able to cover some unique indie bands, and I have found at least one that I would have liked to have, but most of the time, the music I want to listen to is there.

One thing I have found with their range is it’s sometimes too comprehensive. Do we really need 3 or 4 versions of the same album appearing? Or maybe a double or triple album that bands sometimes release to make it easier for new fans to buy the old CD’s.

Stanley Climbfall apears 4 times. Two contain identical bonus tracks, the other two do not. What’s the point in having the non bonus track ones?
Hawkology is actually the first three albums in one. The idea is new fans can get the old albums at a discount when buying old albums. The three albums that are in the Hawkology are available separately (not shown in screenshot)

I will give Sony a plus here though, because it would cost heaps of money to sift through everything and extract actual duplicates, as it could upset some people if there happens to be something in one version of the album that isn’t in the other (maybe an extended track or something,) and I’d rather have more content with a lot of overlaps than it missing one of my favorite songs.

Now, if there are one or two artists that you can’t find, you can upload your own music in a Google Music like style with a program, creatively named, Music Sync. The downside with it, the music can only ever be from one computer. Install it on another computer and all your uploaded songs from previous computers dissapear. It seems strange that they would do this, rather why not just give users some space to upload any songs that they want and be done with it?

Anyway, it seems as though the programs smart enough that it will identify songs that aren’t available from the Sony library, and only uploads them. It also uploads any iTunes playlist if you’re still that (is anyone?) If only they could make a good user interface to match.

Interface
There is no desktop software other than the Music Sync program, it’s all web based. Web and flash based. I personally don’t have anything against Flash, and I can’t say I’m eagerly awaiting the day that HTML5 is the dominant web standard, though on the same token, I don’t loath the day. I’m indifferent what technology is used, as long as it works. If Flash is used and it works well, then that’s great. If HTML5 is used and it works well, that too is great. Given that HTML5 is still upcoming, and it’s probably easier to find Flash developers, it’s not a surprise that the whole site is built around Flash.

My verdict on the overall interface? Well, it works. It’s not absolutely amazing, but it also doesn’t involve lengthy processes and debugging to try and get it working. There are plenty of small annoyances (biggest one so far? leave a song paused for more than a few minutes, and when you come back to playing it, it will start from the beginning), but given the service that it offers, I’m willing to overlook these small things for now. I imagine that Google would do a much better overall if they integrated a subscription service into Google Music (which I can’t imagine happening soon, the major labels won’t even let Google sell music like iTunes, though that could be partly Google’s fault with not wanting to compromise.) So whilst it’s the only service like this (others aren’t available in Australia,) it’s going to get all the money from people that want to use it. The problem they will have is when others do start poping up: due to it’s design, it’s much easier to swap services than it is to swap email addresses (having to let everyone know, forward emails, auto-reply, etc.) or cloud syncing services like Dropbox (having to move over all your files, and working out the deal with shared folders.) You don’t own anything on there, so you move services and you’ve got everything you already had.

So, yes, not an amazing interface, and it has it’s downfalls, but it works. I just can’t get out of my head that Sony is mainly a hardware company, and their software has always been sub-par compared to companies where software comes first (look at what they did to Android! The interface on the X10 is heaps slow and buggy, where as stock Android on the X10 is really good.)

Mobile App

One of the best features is they have released a mobile app for Android, and given what I just said about Sony and making software, it’s surprisingly good. Considering most people would at some stage want to listen  to music on a portable device, and lots of people are starting to use their phones as that portable device. There isn’t really anything much to say about the mobile app. It’s heavily based on the website (though with fewer annoyances, such as the pause issue,) and it works. I still like doubleTwist better, but I was genuinely surprised at how well the Android app worked.

What it’s missing

That definitely is not the right album art.

  • With the Android app, the ability to cache a couple of albums would be awesome. Firstly, it’s going to chew through data, and most phones in Australia are on sub gigabyte data caps (Sony do realise this with a data warning when you start the app, and an option in the settings to stream only when connected to WiFi). It’d be awesome if, when I got up in the morning, connected to WiFi and gave it two albums to cache so I could listen to them on the train. An alternative to this reason would be to make deals with Telcos to make data for Qriocity unlimited, but I doubt that’s going to happen. Second reason, dropouts and congestion. Even if someone has a data plan big enough, mobile data in Australia is much to be desired. I know on a train trip I regularly take there’s about 5 to 10 minutes of no reception, so caching would really help there.
  • Improve the web app. As I said, it’s OK, but not great. It’s really relying on the fact that it’s got millions of songs readily accessible for people to use it. It’d be awesome if they not only had an awesome library, but an awesome media player.
  • Less important, try and cut down on duplicates without removing any content. If the same album appears four times, and they are all identical except one has a couple of bonus tracks, remove all of them except the one with the bonus tracks. No songs are lost, and it’s cleaner overall. That said, I’d much rather have a lot of duplicates than Sony accidentally removing a couple of songs.
  • Also, try and get the right album art for all the albums. There is at least one album I’ve come across with album art that had nothing to do with the artist. It’s not a biggie, but it makes the whole experience seem a little less polished.

Would I recommend it?
Well, I’m not entirely sure. It really depends on who you are. If you love to discover new music (it does have suggestion features built in to find similar artists, but I haven’t tried it) and want to listen to whole albums before you buy it, then it may be for you. If you, like me, listen to most music on a portable device without enough data for regular streaming and have a smaller range of artists, though buy most of the albums from each artist, then you may be better off buying an album a month. That way you own it for ever (well, if you buy it on CD and don’t lose it,) and you don’t need to rely on a data service to be able to listen to music.

Whilst I’ve found it quite good whilst using it on my computer and phone when I’ve had WiFi reception, without the ability to listen to it on the train or in the car without getting “bill shock” when my mobile phone bill comes through, I’m probably not going to renew my accidental subscription when it expires. If they implemented caching on the Android app though, where I could select albums to cache without playing them, then I will reconsider the service.

1000 downloads for Virgin Mobile Australia

Well, I’ve reached 1000 total downloads. Can’t say that I was expecting it to reach that, especially when there’s two on the market (as I’ve mentioned, I didn’t actually find the other one until I was half way through making my own version.)

Moving forward to 10000!

1 more Android app and improvements to Virgin Mobile app

In just a few days I will have finished all my exams for this semester, and will have a good week and bit before I go back to work for the holidays. This means I’ll have some time to work on both the Virgin Mobile app, and a new one. The new one’s a secret for now, but it is another Australian based one.

That said, I’m a firm believer in making quality apps, and there’s definitely a lot of work that I need to put into the Virgin Mobile app, so I’m going to have a good day fixing bugs and making general improvements before I make too much effort on the new app. I’d rather have a handful of quality and well supported apps rather than a large number of half-hearted attempts. So all the ones that I do publish, I do plan on continuing to improve them, both by fixing bugs (most important,) making a better user interface (a new one for Virgin Mobile is coming soon) and adding new features (after the other two things are done.)

The joys of developing software with no API

I’ve finally pushed out my first Android app, one that I’ve put a lot of time into (and still am, got to improve the UI experience and fix up a few bugs!) and one thing I realised in the development process is, it isn’t fun trying to develop for something that has no external API, or a company that even wants this to happen.

In the development process, I have been blocked from logging into Virgin Mobile’s website, where I just kept getting 404 Not Found or 405 Not Allowed errors (fun times.) That said, it was linked to my IP address, not my account, because it worked when I tried it at uni. And right now, I can no longer pay any bill by credit card, as I made a few mistakes in a yet unreleased feature (though I’m sure you can guess,) and whilst those mistakes have been fixed in the program (I think), I cannot make payments to my from my IP address (changed IP address, same problem), account (tried a different account, same problem) credit card, making it very hard to test.

Not to mention the lack of ability to simulate events that either don’t happen that often (turn of the month, to ensure that the app handles data and months properly,) or that you don’t ever want to happen (overdue bill.) I can also only test it on my own account, which severely limits the testing scope. I do have a friend from Uni who I get to do beta testing, but without many different accounts at your disposal and connected to your debugger, it does make finding and fixing bugs quite difficult. For example, I have had 2 bugs so far that I cannot simulate, I can’t work out why the data isn’t been fetched properly without an account that it happens on. One of them I’ve put in if and try…catch statements that prevents the error from happening, but it comes at a cost (the data usage for that user will not be displayed. That said, maybe Virgin Mobile still have postpaid accounts without data? If so, the bug should be fixed.) What I really need is users to bombard me with emails, screenshots of their account and the HTML source code of some of their account pages (I don’t need username and passwords, just the user to be willing to test it after I’ve made a few changes.)

It’s also annoying when you can only work with the information you’re given, but that information isn’t available. For example, I want to have a progress bar throughout the month of how much credit the person has used, but I can’t find anywhere on the accounts page a value that states how much credit the user has in their cap (it does for data, but not for cap credit.) I’ve tried to overcome this by detecting the type of cap (that information is available,) and storing the credit allowance and the amount for that cap in the code of the program, and matching it up. This isn’t the best way to do it (though it’s the only way I can,) as I have to manually keep it updated, and what if it’s wrong? To overcome it been wrong I’ve set it to alert the user when they login what the cap is detected as, and that they can change it if it’s wrong, but it’s better when the user has to input as few things as possible. I’m just getting away with username and password, I’m hoping when I implement a prepaid account it can automatically be detected (which reminds me, I need to run out tomorrow and get a prepaid SIM, I need an account to test it with!)

I haven’t yet heard from Virgin about unusual activity on my account, and I hope to keep it that way, but there’s only so much you can develop without actually testing it on your own account a few times, and things inevitably go wrong. It would be nice if Virgin Mobile released an official app, or an API, as it is what users want.