Thursday, April 22, 2010

Android YouTube Intent

For a long time I've wondered how to show a YouTube video to the user in an Android application. There's this awesome post published by KeyesLabs on how to create your own Activity that plays YouTube videos. It's great, and you should definitely use it. But I think you can improve on that. It would be very useful for the user to view that video in the default YouTube player installed on the device because this way they can save it (like it, rate it, save it to their profile) plus enjoy other improvements and features the official YouTube app provides (plus probably better error checking for unavailable videos and so on).

While I was playing around with the emulator, I noticed that if you try to view a YouTube video in it th browser gives an error similar to Cannot open the page at vnd.youtube:VIDEO_ID?some=other¶meters=here. This way, I learned that a VIEW intent with a data URI like vnd.youtube:VIDEO_ID will launch the official YouTube app (this was confirmed by some nice folks on IRC, as I don't have an Android device). Basically:

Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:VIDEO_ID")); startActivity(i);

Will launch the YouTube app and watch the video with ID VIDEO_ID. Couple this with the Activity on KeyesLabs' blog and the Can I use this Intent? article and you've got a winner. My final solution is:

private void startVideo(String videoID) { // default youtube app Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:" + videoID)); List<ResolveInfo> list = getPackageManager().queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY); if (list.size() == 0) { // default youtube app not present or doesn't conform to the standard we know // use our own activity i = new Intent(getApplicationContext(), YouTube.class); i.putExtra("VIDEO_ID", videoID); } startActivity(i); }

Wednesday, April 14, 2010

How-to: Android Favorite Button (the right way, this time)

My last blog post is about how to make a favorite button in an Android application. It is wrong, those drawables should not be used independently. Instead, the @android:drawable/btn_star resource should be used, as it is a state-drawable and contains all the possible states (checked, unchecked, checked and focused, checked and clicked, ...). The proper way to use this is:

<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:button="@android:drawable/btn_star"/>

The result looks exactly like the button used in Android's Contacts application when viewing a contact (upper-right corner).

Man, that took some digging.

Monday, April 12, 2010

Android Favorite Button

I love Android. What I hate about it, though, is that they don't tell you how to make standard-looking UIs. For example, I had to dig through source codes to find the @android:style/ButtonBar style that you can use as the style on pretty much any layout (RelativeLayout, LinearLayout, etc.) which provides a nice background graphic for your button bars. Anyway, today I discovered another such hidden feature – a star drawable that can be used for favorite buttons. However, I still don't understand a thing: there's btn_star, btn_star_big_off and btn_star_big_on. One would think "how do I get btn_star_on then?", but then one would realize btn_star and btn_star_big_* are the same size (all of these are in @android:drawable/). In short, to create a favorite button/image, use: <ImageView android:src="@android:drawable/btn_star_big_off"/> <!-- or, if you want the button-like background and borders (although I prefer the ImageView version) --> <ImageButton android:src="@android:drawable/btn_star_big_on"/>

Friday, April 2, 2010

How to properly write JavaScript libraries

I've seen JavaScript code written in all the possible ways. The reason there are so many ways to do it is because JavaScript is incredibly flexible. But that flexibility makes people write really ugly code. Examples of ugly, unreadable, error-prone code:

(function(window, undefined) { var myLibrary = (function () { var someProp = "..."; function someFunc() { ... var myLibrary = (function () { var someProp = "..."; function someFunc() { ...

If you write JavaScript like that, stop. Here's the proper way to write JavaScript libraries:

function Example() { if (!(this instanceof Example)) { // in case whoever used this forgot to use the `new' keyword return new Example(); } Example.staticMethod(); this.instanceMethod(); // for any timeouts/events, do this: var instance = this; setTimeout(function() { instance.instanceMethod(); }, 200); } Example.staticMethod = function() { // do something here; } Example.prototype.instanceMethod = function() { // do something here } // instantiate the Example class: var example = new Example();

Isn't this much more beautiful? The reason for the instance variable needed in timeouts and events is that, in JavaScript, when handlers are called, they are called in the window context. That means that inside the handler, the keyword this refers to the global object window. By using the instance variable we are working around this, calling the handler with the correct context.

Inspired by this stackoverflow question.