Friday, January 22, 2010

Viewing source in eclipse with Android SDK (the easy way)

Forgot to mention, I finally got that article up on viewing source in Eclipse. I found the resources on how to do it weeks ago but wanted to write it up properly with screenshots and everything and was too busy! Anyway it’s over here:

http://android.opensourceror.org/2010/01/18/android-source/

I have a few things yet to do though:

  • This gives some hints on getting exactly the right version of source as opposed to a branch
  • Need to alter my published sources to comply with the license (oops)
  • Move the images and downloads to better hosting :-/

In other news, I need to look through this thread and see if I can get debugging a device to work in Fedora 12.

[Via http://sosiouxme.wordpress.com]

Wednesday, January 20, 2010

One month with the Motorola Droid

I purchased my Motorola Droid on December 18th after months of debating whether to leave Verizon Wireless, my former employer, for the iPhone.  Before the Droid was released I was given the opportunity to play around with it as well as the Droid Eris.  At the time I was really disappointed.  The keyboard, which I rarely use now, is awful.  Actually it’s a complete waste.  In fact, I wish someone would come out with a case that would lock the keyboard completely.  Another issue I had at the time was the speed of the internet. It was slow…Slower than any of the other Rev. A products I have used.  My mind was set, I was making the move to AT&T and the iPhone.  Then something happened that changed my mind.

I received in the mail $75 off the Motorola Droid if I purchased the device through Telesales.  Hmmm…as a former employee I wasn’t eligible for a New Every Two because I was on a 1 year contract.  Now with the flyer the Droid was looking a lot sweeter.  The Droid was $299.99 on a two year contract and you received a $100 rebate. Now after the additional $75 off the Droid was only $124.99.  Plus I was able to get my wife the Droid Eris for FREEEEEEEE! (Just watched that Adam Sandler movie with my kids the other day.) So lets see, I can pay $124.99 for two phones or buy the iPhone for $299 a piece.  Not to sound cheap but come on.  Are you kidding me?  Add the AT&T activation fees into the equation and staying with Verizon Wireless sounds even sweeter.

Another issue that made my decision a no brainer.  Service, Service, Service!  I didn’t know how good I had it with VZW until I started carrying a competitors device.  It was a Sprint Curve 8350i.  Wholly cow! I can’t believe they charge for their service.  They should pay me to carry that phone.  I thought if the Sprint phone is this bad I better check around to see what my friends around town thought about their AT&T service.  Call one, went something like this…

Me – “Eug, how is the service on your iPhone?”

Eug – “Dude, stay with Verizon. I’m trying to get out of my contract. This service sucks”

After a few more of those calls my mind was made up.  I would sacrifice the “cool” factor for money and service.

So, It’s been a month and I f-ing love it.  I can do everything I want on the Droid and more.  I have played with the iPhone on multiple occasions and I honestly don’t yearn for it like I once did.  The Screen on the Droid is unbelievable.  Before the Droid I had the Blackberry Storm.  The screen on the Storm was beautiful.  This one blows it away.

The touch screen keyboard works flawlessly.  In addition, I was able to install the Swype Beta which I gotta say works like a charm as well.  I will talk about apps at another time.  Both the portrait and landscape  touch screen keyboards are accurate and the word prediction works flawlessly when you do mistype a word.  As far as the slide out keyboard goes, I never use it as I stated earlier.  What I like most about the Droid and all Android devices for that matter is the ability to customize.

Practically right out of the box you can make changes to the devices appearance and  functionality.  You make the device work for you rather than you figuring out how to change your habits for the device.  I was primarily a Blackberry user before I got the Droid.  I had an 8830, 8330, Storm and a 8350i.  I was a true Crackberry addict.  I am now a Droiddict.  I am able to get all the information I want as I want it by using pre-installed and downloaded widgets.  With apps like Beautiful Home, Better Cuts, Open Home, Better Keyboard, Home ++, Sweeter Homes, dxTop, GDE and aHome you can customize the phone in ways that make iPhone users envious.  In order to do some of these things on an iPhone you need to root the device.  Not on an Android device, the option to root the device is there but it isn’t necessary.  As far as apps go, iPhone has the volume and the quality but the Android market will catch up in quality.

In the past month I have downloaded my fair share of apps.  Some I kept some I deleted right away. Are they all pretty…hell no!  Are they improving with every update…hell yes! There may not be the volume of apps but the apps you want are available and if they’re not, they soon will be.  You have to remember, the app store wasn’t packed with apps the first day it opened up.  How long did it take to get to the point it is today?  I am a gadget geek.  I have a Slingbox and a Squeezebox at home.  I am itching to get the Slingplayer on my Droid.  I have updated my Beta page on Sling Media’s site so I can test it out when released.  I am also waiting for an iPeng like controller for my Droid.  There are a few adequate apps out there for the Squeezebox but none of them have iPeng’s functionality yet.  I know they will come, just like they did for the iPhone.

That’s about all the writing time I have…Wife is out and the kids and the puppy are starting to drive me crazy.  I think I’m developing a twitch?!?

[Via http://awlon.wordpress.com]

Monday, January 18, 2010

The Nexus One is not for you

Look, I love my Nexus One. But it's not for everyone. In fact, I'd suggest it's not for most people. If you're a whiner, don't even THINK about getting this phone. Not yet, anyway. Google isn't about delivering a finished product. And the Nexus One is far from a finished product. It has some of the smartest people in the world developing for it and working on it which means that between today and tomorrow you'll likely be able to SEE it change. But I'll guarantee there's something wrong now, today, that'll drive you absolutely batty if you let it. So, if you're a whiner, or if you want a phone that's a finished product, please stay away. If you like to fiddle with things, open them up, see what's inside and tinker then you should consider the Nexus One because that's pretty much a requirement. Do you have to be Linux knowledgable? Not necessarily but it sure helps. If you know what root or superuser is then you're ahead of the game. If you're adventurous and like to learn new things, then this may be the phone for you.

Here's a checklist:

The Nexus One is not an iPhone, it's not even an iPhone competitor.

If you've got an iPhone, chances are you're an iTunes user. This phone doesn't come with iTunes integration. Yes, you can download an app that will integrate it with iTunes but if you're an iTunes user, get something else.

Some apps that are available for the iPhone are available for the Nexus One but many are not.

If you're looking to replace your iPhone and you have apps that you absolutely depend on, don't switch. You'll just get annoyed and waste your time. You can look for similar apps or even ask the developer if the app is avaliable on Android or the Nexus One but it'll look different and act different. See my first point, above.

The Nexus One is not "finished".

Apple delivers consumer quality products that are pretty nearly "done". Google doesn't do that. If you want something that "just works". get an iPhone. Like their online offerings, Google delivers products that are pretty close to complete but you can bet they'll have to rev the software and, until they do, you either have to live with the problems or find a way to fix it yourself. Don't get me wrong, there are a LOT of people out there who can help you fix it but they aren't Google.

You get a charge out of seeing a Linux command prompt

The Nexus One may be for you. I log in to my phone at least daily and do things that I could do via the phone's GUI but I find it easier and quicker to do a lot of things this way. If you're uncomfortable with the command line, consider something else.

You've got a lot of MP3s.

Not just music files in some format but files that end in ".mp3", are VBR or CBR, up to 320Kbps. Or you've got a lot of Ogg Vorbis files. If so, consider the Nexus One. But If you've for DRM WMA files, forget it cuz it won't play 'em.

You stream Slacker or Pandora or Shoutcast.

There are apps for these services. Slacker and Pandora apps come from Slacker and Pandora. There are several apps that stream Shoutcast quite easily. No, I don't know what the iPhone app looks like. If you care, you shouldn't be considering the Nexus One.

There are loads of other things I could suggest but, honestly, if you're hesitant about getting a Nexus One then please don't. You may be happy but, then again, you may not. As Rober Heinlein said, never try to teach a pig to sing. It wastes your time and annoys the pig.

[Via http://links.wordpress.com]

Friday, January 15, 2010

How to Unlock and Root a Nexus One

http://www.slashgear.com/wp-content/uploads/2009/12/rootednexusone1.jpgSo I came across something that most of you Nexus One owners might be interested in: How to Unlock and Root your Nexus One.

Thanks to the people over at Androidandme, have all the step by step video guide to unlocking your Nexus One.

Heres the link to it: Unlock and Root Your Nexus One

-=WARNING!=- Please ONLY do it if you know what you’re doing and you feel comfortable doing it. Don’t come running to me or Androidandme saying you messed up your phone because you couldn’t follow simple guidelines.

[Via http://fiercetechnology.com]

Wednesday, January 13, 2010

Writing your own ContentProvider

Hey everyone,

So the following tutorial will hopefully give you a good idea of how to implement your own ContentProvider. I know that there are a lot of pretty good sites out there with some good code snippets, but I’ve noticed that not many really help the developer understand what’s going on step by step so my goal is to not only provide an example of a fully implemented ContentProvider but also to step you through the process.

So I’ll start by just posting all of the code, and I’ll go through it slowly afterwards. We’ll start with the Custom Content Provider itself:

package jason.wei.apps.securenotes.providers; import jason.wei.apps.securenotes.db.Note.Notes; import java.util.HashMap; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.util.Log; /** * @author Jason Wei * */ public class NotesContentProvider extends ContentProvider { private static final String TAG = "NotesContentProvider"; private static final String DATABASE_NAME = "notes.db"; private static final int DATABASE_VERSION = 1; private static final String NOTES_TABLE_NAME = "notes"; public static final String AUTHORITY = "jason.wei.apps.notes.providers.NotesContentProvider"; private static final UriMatcher sUriMatcher; private static final int NOTES = 1; private static HashMap notesProjectionMap; private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " (" + Notes.NOTE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + Notes.TITLE + " VARCHAR(255)," + Notes.TEXT + " LONGTEXT" + ");"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS " + NOTES_TABLE_NAME); onCreate(db); } } private DatabaseHelper dbHelper; @Override public int delete(Uri uri, String where, String[] whereArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { case NOTES: count = db.delete(NOTES_TABLE_NAME, where, whereArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { case NOTES: return Notes.CONTENT_TYPE; default: throw new IllegalArgumentException("Unknown URI " + uri); } } @Override public Uri insert(Uri uri, ContentValues initialValues) { if (sUriMatcher.match(uri) != NOTES) { throw new IllegalArgumentException("Unknown URI " + uri); } ContentValues values; if (initialValues != null) { values = new ContentValues(initialValues); } else { values = new ContentValues(); } SQLiteDatabase db = dbHelper.getWritableDatabase(); long rowId = db.insert(NOTES_TABLE_NAME, Notes.TEXT, values); if (rowId > 0) { Uri noteUri = ContentUris.withAppendedId(Notes.CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(noteUri, null); return noteUri; } throw new SQLException("Failed to insert row into " + uri); } @Override public boolean onCreate() { dbHelper = new DatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (sUriMatcher.match(uri)) { case NOTES: qb.setTables(NOTES_TABLE_NAME); qb.setProjectionMap(notesProjectionMap); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { case NOTES: count = db.update(NOTES_TABLE_NAME, values, where, whereArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } static { sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(AUTHORITY, NOTES_TABLE_NAME, NOTES); notesProjectionMap = new HashMap(); notesProjectionMap.put(Notes.NOTE_ID, Notes.NOTE_ID); notesProjectionMap.put(Notes.TITLE, Notes.TITLE); notesProjectionMap.put(Notes.TEXT, Notes.TEXT); } }

And next a little helper class that keeps all of the columns organized and readily accessible:

public class Note { public Note() { } public static final class Notes implements BaseColumns { private Notes() { } public static final Uri CONTENT_URI = Uri.parse("content://" + NotesContentProvider.AUTHORITY + "/notes"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.jwei512.notes"; public static final String NOTE_ID = "_id"; public static final String TITLE = "title"; public static final String TEXT = "text"; } }

(Note that this is similar to how Google provides you with the columns, i.e. People._ID, People.NUMBER, CallLog.CACHED_NAME, etc)

Okay so let’s go through this step by step. First, when you extend ContentResolver, there are 6 methods you need to overwrite:

query()

insert()

update()

delete()

getType()

onCreate()

Normally these are just wrapper functions around the raw SQL queries. For instance, the method:

db.delete(tableName, where, whereArgs);

Is simply just a wrapper around the SQL query that looks something like:

"delete from " + tableName + " where " + where + " ? " + whereArgs"

So for those who know SQL, if I wanted to delete the note with title “Hello World” then my queries would look like:

// wrapper query db.delete(NOTES_TABLE_NAME, Notes.TITLE + "= ' " + "Hello World" + " ' ", null); // real query when translated String query = "delete from notes where title = 'Hello World' ";

And so as you look at how I overwrite the 6 methods, you’ll see that I’m simply taking in the parameters and inputting them appropriately into the wrapper methods. Of course, you can override them as you like depending on what you want your application to do. Perhaps your application is ONLY worried about retrieving the average of some numbers. Then in your query() method, maybe instead of querying for the numbers normally, and then always having to iterate through the numbers and find the average from the JAVA side, you could customize your query to automatically return the average BY DEFAULT.

But in case you’re still confused, let’s look at an example:

public int delete(Uri uri, String where, String[] whereArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { case NOTES: count = db.delete(NOTES_TABLE_NAME, where, whereArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; }

So basically you pass in the Uri (in our case it will be Notes.CONTENT_URI to tell the system which table you’re going to target) and if the Uri matches NOTES then we use our SQLiteDatabase (retrieved in the first line) to delete from the notes table using the where arguments passed in.

A similar idea goes into overriding query(), insert(), and update(), and in our onCreate() method we are simply using our SQLiteDatabase to execute a CREATE TABLE statement where we build our table using our defined columns (i.e. Notes.NOTE_ID, Notes.TITLE, and Notes.TEXT) and also make sure we use the proper SQLite3 column types.

One thing to note here is that Android requires that the unique id column have name “_id”.

This is extremely important as otherwise your content provider will not get registered properly.

Now, one last thing before I get to how you register it in your Manifest is what this AUTHORITY String is all about. In my case it was:

public static final String AUTHORITY = "jason.wei.apps.notes.providers.NotesContentProvider";

So the authority you can more or less define in anyway that you like, but typically it will look something like:

{package name}.providers.{Custom Provider name}

For organizational purposes, this means that in your Android project, you will have to create a new package called:

{package name}.providers

In order for the Uri path to be correct (again pretty obvious, but who knows).

And so this AUTHORITY basically just helps you define the CONTENT_URI of your ContentProvider (i.e. the path to your database), and you will register your provider in your Manifest like so:

And so you see that I define my content providers in a way such that the project path is equal to the authorities path (again, not required, but probably recommended for simplicity and organizational issues).

And that’s it! Now you have a fully registered and created ContentProvider. My next example/tutorial will show you how to write cool wrapper functions that help you make queries and manipulate data in whatever way you want!

Let me know if you have questions, otherwise Happy Coding.

- jwei

[Via http://thinkandroid.wordpress.com]

The battle of the SmartPhone and its effect on mobile networks

Third generation (3G) mobile networks are also suffering from the knock on effects of the snow. To be honest I am not surprised, we have recently seen an explosion in the download of ‘Apps’, mainly down to the mass adoption of the Apple iPhone.  The Apple app store has gone from an incredible two  to three  billion downloads in the last four months. This staggering figure undeniably puts further pressure on mobile network providers; O2, Orange, Vodafone and Tesco (although Tesco use the O2 network).

The app’s available to customers on the iPhone are without doubt one of its key differentiators and a very significant part of its current competitive advantage.  However, Google’s exciting new release Android looks set to challenge their stronghold.

It’s important to take a minute though and think about how this increase in competition between the two manufacturers will affect consumers.  Demand for apps will start to become a basic expectation for mobile users in the next few years rather than the luxury of a select few.

Increased consumer demand for Apps are already proving a challenge for networks.  O2 were reported to experience limited network availability just before Christmas.

At the moment apps are mainly used in mass by iPhone users. iPhone users currently run one application at a time, therefore only running one update across the network at that time. However, Google’s Android can run multiple applications thus multiple updates, opening up our networks to increased congestion.

I think 2010 will be an interesting year for mobile network providers, as they all seek to raise their game and accommodate demand. What’s bad for us (consumers) is the immediate answer is to cap bandwidth and increase prices. We could also potentially suffer from reduced availability.

One thing’s for sure; 2010 WILL be the battle of the SmartPhone – Android vs iPhone.  It will also be a battle for the providers… let’s hope when fourth generation (4G) mobile networks come of age in the next five years that such network capacity will be a thing of the past…  :)

[Via http://100daysinthecloud.wordpress.com]

Monday, January 11, 2010

Is Google's Nexus One A Gaming Contender?

There have been several recent articles written on whether or not Android-based phones (and specifically the Nexus One) are going to be good for game developers.

Is Google Nexus One A Gaming Contender?

Gaming on the Google Phone?

The arguments come down to:

  • The Android Market is still not a very robust storefront and not as polished as Apple’s.
  • Lack of multi-touch limits the user-input capabilities
  • Limitations of the “sandbox”-ing strategy Google has used. Specifically, only being able to run apps that fit in the 512MB of internal storage. Not a huge problem for many games, but makes the IPhone Myst implementation a non-starter.
  • Concerns about the need to support multiple configurations of apps in the field. Right now iPhone has really two versions. If every Android phone has slightly different capabilities, that could be a nightmare.

In particular, I wanted to call out some articles about GameLoft, one of the biggest mobile game developers. A recent article outlines their celebration of the 10 millionth App Store download of their titles. Not too long ago they announced that they were significantly cutting back on Android development. Can the iPhone gold rush repeat itself on Android? Only time will tell.

[Via http://shaunkime.wordpress.com]