Setting up a Native Build Environment for Android

My initial attempts at cross compiling Mono were on Scratchbox. But Scratchbox was having technical difficulties building Mono from the trunk (not sure why), did not have a working apt-get, the Mono binary would not actually run when it did build, etc. What I really wanted was to do real native builds. However, the G1/Dream has limited RAM (96MB total I think). As a result, compilation took forever, and often the watchdog daemon would kick in and restart the phone due to unresponsiveness. So that is not an ideal build environment. So my solution was to get Debian running on the Android emulator.

I figured it would be straightforward enough, but I ran into a snag mounting the ext2 image containing the Debian boot strap. That was solved by recompiling the Android Kernel with ext2 support added:

  1. Follow these directions to prepare to build the kernel.
  2. Before building the kernel, run make menuconfig, and add ext2.
  3. Now make.

That will give you a an image with ext2 compiled into the kernel. For the lazy, click here for the compiled kernel image. 

When you start the emulator from the command line, use the following flags:

emulator -kernel zImage -sdcard sdcard.img -qemu -m 512 # The '-qemu -m 512' options tells qemu to start with 512MB of virtual RAM!

Now install Debian with the same instructions Saurik's post. Note that you will not need to insmod the ext2.ko module. Always remember to unmount the ext2 partition before closing the emulator. Otherwise you may end up getting some nondescript NFS error; probably a result of file system corruption. However, this is fixable by mounting the ext2 file in Linux and running the fsck tool.

My 2009 (Mostly) Mobile Predictions

miss-cleo

Apparently making wild predictions is the hip thing to do on New Years, so count me in.

  • We will receive confirmation that Netflix will provide their Watch Now service to Windows Mobile devices via Silverlight.
  • iPhone sales will slip in Q4 as Android devices and applications proliferate.
  • The MSM720X line of chips will become obsolete. Hell, in my opinion they already are. Basically any MSM720X based phone I have used slows to a crawl when accessing a network (including the Dream). These things are just slow (though the OpenGL acceleration is great). So as a result:
    • Intel and/or NVidia will become the new big players in the mobile chipset arena.
    • HTC, who is heavily invested in the MSM720X line of chips, will not be able to crank out incremental revisions of the same old phone in a new package (Touch, Polaris, Diamond, Raphael, Dream, HD, MAX, Viva, S7X0, etc, etc). They'll probably need to completely redesign their phone architecture. As a result, their domination of the Windows Mobile market will end.
    • Samsung, Sony, and Motorola will begin releasing touch phone products that are superior to the HTC brand.
  • Digital Cable subscriptions decline. Netflix subscriptions increase. Cable companies start lowering rates and come to terms with the fact that they are just ISPs.
  • Unlimited SMS becomes a staple in a mobile phone plan due to it's necessity in doing proper push email (push anything really).
  • Zune phone will be announced.
  • Consumers start buying Zunes. iPod sales slip in Q4.
  • Linux will continue not being a mainstream desktop OS. (Hey, I use it on a daily basis. It's still not mainstream.)
  • Microsoft spends an insane amount of money buying something mobile related in an attempt to fix their Windows Mobile situation.
  • Sprint goes belly up.

Source Code License Change

Quick heads up for those using my code: I've changed the licensing from Creative Commons to Do What The Fuck You Want To Public License (WTFPL). Yes, it is a legitimate license, and I feel it better represents my stance on software licensing.

WindowlessControls Tutorial - Part 3

Cross compiling Mono is making me quite the productive blogger! This tutorial will expand on the ImageButtons I used in the previous tutorial. The buttons we placed only had a single image: nothing happens when they are focused or clicked. However, the class does support animated buttons! Using the previous tutorial code as a base to set up our background, I will add the new animated buttons:

// focus state bitmap
PlatformBitmap focused = PlatformBitmap.FromResource("Btn1.png");
// normal unselected state bitmap
PlatformBitmap unfocused = PlatformBitmap.FromResource("Btn1_Disabled.png");
// clicked state bitmap
PlatformBitmap clicked = PlatformBitmap.FromResource("Btn1_Pushed.png");

// set up the image button by setting the properties manually
ImageButton button1 = new ImageButton(unfocused, Stretch.None);
button1.Control.FocusedBitmap = focused;
button1.Control.ClickedBitmap = clicked;
button1.BackColor = Color.Transparent;

// OR set the button up by setting everything in the constructor
ImageButton button2 = new ImageButton(unfocused, Stretch.None, focused, clicked);
button2.BackColor = Color.Transparent;

// add the buttons
wrap.Controls.Add(button1);
wrap.Controls.Add(button2);

All you need to do is specify the images for the various button states, and the button will handle the animations for you! Click here for the updated tutorial source code.

Mono on Android - Success At Last!

Last week, I blogged about my attempts to get Mono running on Android. I was running into a nasty Illegal Instruction issue, which I didn't look into further until today. And after implementing a quick hack/fix I got it working!

After running strace on Mono, I was able to determine that the Illegal Instruction was occuring in mini-arm.c in the mono_arch_flush_icache function. I wasn't able to decipher whether the inline assembly was correct or not; but I got the jist of what it was trying to do: it was calling cacheflush, but failing with the Illegal Instruction in there. I looked at the mini-x86.c and saw that the equivalent mono_arch_flush_icache was empty; the comment indicating it was "not needed". I don't know if this is some vestigial code or what, but I figured it would be relatively benign to not flush the instruction cache and just see what happens. And the grand results:

root@localhost:~/Desktop# mono test.exe

Hello World

This would not be possible without the help of my co-worker, Kevin Eustice, and my abhorrence towards Java.

Expect to see some performance comparisons between Mono vs Dalvik shortly! Though I don't expect it to even be a fair competition, because Dalvik does not JIT. Lame.

WindowlessControls Tutorial Part 2

It's late, and I'm waiting for Mono to finish cross compiling for Android (hopefully with better results), so I figured I'd write up the next part of the WindowlessControls Tutorial series.

Recently, Chris Craft blogged about Alpha Blending in .NET Compact Framework. One of his suggestions was to use the Alpha Mobile Controls. After using and learning that API bit, you will quickly discover that in practice, it is not really usable. When I initially began investigation into Alpha Blending controls, I took the same approach as Alpha Mobile Controls. This design ended up hitting a dead end due to layout issues, and difficulty in actually reusing controls. It made me rethink how to implement a mobile UI framework. The requirements then ballooned and I ended up implementing WindowlessControls.

In In this article, I will demonstrate usage of the following:

  • How to use the WrapPanel, another common layout element. A WrapPanel aligns elements either side by side or top to bottom in a given direction. When it runs out of room in that direction, it will wrap to the next line. This works just like WPF's WrapPanel.
  • How to use the OverlayPanel. The OverlayPanel allows you to layer controls on top of each other.
  • The ImageButton class - A clickable button that displays an image. This image can have alpha.
  • How to enable transparencies in WindowlessControls.

Let's start with these three images:

Wallpaper users tip

The first image will become the background for our form. The next two images will be transparent buttons on that background (the black/gray area is actually transparent, the blog is munging it).

To do this, we will need to create an OverlayPanel. This OverlayPanel will contain two other controls: a background and a foreground. The background will be a WindowlessImage containing the leaf bitmap. The foreground will be a WrapPanel containing the two ImageButtons. Let's see what this looks like in code:

 

public AlphaDemo()
{
    InitializeComponent();

    // we need to layer two controls on top of another: a background, with another panel containing more controls
    StackPanel stack = myHost.Control;
    OverlayPanel overlay = new OverlayPanel();
    stack.Controls.Add(overlay);

    // set up the background bitmap and control
    PlatformBitmap backgroundBitmap = PlatformBitmap.FromResource("Wallpaper.jpg");
    WindowlessImage background = new WindowlessImage(backgroundBitmap);
    background.Stretch = Stretch.Uniform;
    overlay.Controls.Add(background);

    // set up the foreground
    StackPanel foreground = new StackPanel();
    overlay.Controls.Add(foreground);

    // load the transparent images
    PlatformBitmap users = PlatformBitmap.FromResource("users.png");
    PlatformBitmap tip = PlatformBitmap.FromResource("tip.png");

    // the two buttons will be placed in a WrapPanel
    // a wrap panel will horizontally or vertically lay out elements in a given direction until it runs out of room in that direction.
    // when it runs out of room, it will "wrap" to the next line.
    // since this wrap panel is contained in a vertical stack panel, it will lay out elements horizontally, and wrap vertically to the next line.
    WrapPanel wrap = new WrapPanel();
    foreground.Controls.Add(wrap);

    // set up the users button
    ImageButton userButton = new ImageButton(users, Stretch.None);
    // controls must be explicitly marked as being transparent. transparency is disabled by default on controls for performance reasons.
    userButton.BackColor = Color.Transparent;
    wrap.Controls.Add(userButton);
    userButton.WindowlessClick += (s, e) =>
    {
        MessageBox.Show("You just clicked users!");
    };

    // set up a tip button next to the users
    ImageButton tipButton = new ImageButton(tip, Stretch.None);
    tipButton.BackColor = Color.Transparent;
    wrap.Controls.Add(tipButton);
    tipButton.WindowlessClick += (s, e) =>
    {
        MessageBox.Show("You just clicked the tip!");
    };
}

And when you run this code, you see the following buttons which support transparencies. Notice that in the portrait, the second button can't fit on the first line, so it wraps to the next line. But if you rotate the orientation, it no longer needs to wrap, and comes back up to the first line. That's the WrapPanel in action!

image image

Cool huh!? As the code comment says, transparencies are disabled by default. This is because performing alpha computations is very expensive, and should only be used on an as needed basis. Click here for the updated tutorial.

Windowless Controls Tutorial Part 1 - Continued

In my previous post, a reader mentioned that he was curious what happens to this tutorial when it is run a device that has a different form factor, or the screen is rotated. Well, the WindowlessControl system resizes and remeasures all its components of course!

image

But there's a problem, the image is scrolled off the screen! Let's fix that with a little code. Let's enable AutoScroll on "myHost" and then place a another VerticalStackPanelHost inside it that will then contain all the controls seen in this form. The myHost control will allow the new VerticalStackPanelHost to size vertically to whatever length it pleases, and show scroll bars automatically, as necessary. So, the modified constructor looks like this:

public HelloWorld()
{
InitializeComponent();

// myHost is a Control that provides a transition from System.Windows.Forms to WindowlessControls.
// myHost.Control is the WindowlessControls.WindowlessControl that is "hosted" in the Windows.Windows.Forms.Control.
// put all the forms contents into a scrollHost, which will resize arbitrarily to fit its contents
VerticalStackPanelHost scrollHost = new VerticalStackPanelHost();
StackPanel stack = scrollHost.Control;
stack.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Stretch;
myHost.Control.Controls.Add(scrollHost);

// enable auto scrolling on myHost so if the contents (scrollHost) are too big, scroll bars appear
myHost.AutoScroll = true;






 



image



This form will now automatically set itself up properly and show scroll bars as necessary! Click here for the updated source code.

WindowlessControls Tutorial Part 1

I've mentioned in passing several times that I use a home brew UI framework to do all my Windows Mobile development. The UI framework implements many things that are missing from System.Windows.Forms:

  • Relative Layout of Screen Elements - Controls are positioned relative to each other and to the screen, not at absolute positions, which is the behavior of Windows Forms. The benefit of relative layout is that your form can fit any screen form factor.
  • Transparent Controls - There are ways to get transparencies into Windows Mobile, but none elegant.
  • Smart Key Navigation - Up, down, left, and right actually navigate you in that direction. Very handy for non-touch screens.
  • Data Driven Controls - Controls are driven by the data they represent. This allows for a clean MVC pattern which is not available with Windows Forms.
  • Simple Animation System - Creating and handling "focus" and "click" states for buttons is very simple.
  • Custom Controls - This framework can be used to create rich custom controls quite easily.
  • Hierarchical Events - All events bubble upwards in the control hierarchy and can be handled at any level. Similar to WPF.
  • XAML style layout - Create your user interface using XML.

This framework can and has been used to create aesthetically pleasing applications, such as Klaxon; something that is generally very difficult to do in Windows Mobile. However, for tutorial purposes, I'm going to start with a very simple "Hello World" style application. This tutorial will demonstrate the following (click here for the source code):

  • Add a WindowlessControl "Host" to your Windows Form application.
  • Add controls to the "Host" to be handled by the layout and rendering engine.
  • Manipulate the layout of these controls.
  • Handle click events at different points in the control hierarchy.
  • Draw some text and a simple image.

WindowlessControls is a complete layout and rendering system. You can drop a WindowlessControl "Host" onto a Windows Form, and then begin adding other WindowlessControls into it to take advantage of its features.

  1. Create a Windows Mobile Windows Forms application.
  2. Add a Reference to WindowlessControls.
  3. Compile.
  4. Drag a VerticalStackPanelHost (named myHost below) onto the Form. Dock the VerticalStackPanelHost so it fills the entire form. This will become your gateway into the land of WindowlessControls. A StackPanel is similar to the WPF StackPanel. It lays out all elements inside it in a linear fashion. A VerticalStackPanelHost would thus lay out all elements vertically.

image

Now you are ready to add controls. First, let's add a simple label that says "Hello World!". We'll add this code into the Form's constructor:

public HelloWorld()
{
    InitializeComponent();

    // myHost is a Control that provides a transition from System.Windows.Forms to WindowlessControls.
    // myHost.Control is the WindowlessControls.WindowlessControl that is "hosted" in the Windows.Windows.Forms.Control.
    StackPanel stack = myHost.Control;
    // make the stack panel to stretch to fit the width of the screen
    stack.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Stretch;

    // hello world!
    WindowlessLabel hello1 = new WindowlessLabel("Hello World!");
    stack.Controls.Add(hello1);

That was painless enough. This will produce the left aligned "Hello World!" seen here:

image

Now let's try adding some larger text that is centered horizontally and some text that is right aligned:

// center this label and use a different font
Font center = new Font(FontFamily.GenericSerif, 20, FontStyle.Regular);
WindowlessLabel hello2 = new WindowlessLabel("Centered!", center);
hello2.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;
stack.Controls.Add(hello2);

// right align this control
WindowlessLabel right = new WindowlessLabel("Right Aligned!");
right.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Right;
stack.Controls.Add(right);

image

Notice that there is no need to specify any positioning with the various screen elements. All their heights and widths are calculated by the layout system, and the labels are "stacked" on top of each other automatically. Another supported property of any WindowlessControl is a "Margin". This allows the developer to specify a small amount of padding between the Control and its content. For example, to draw some text with a 20 pixel margin all around it, set the Margin property:

// show that controls support margins
WindowlessLabel margin = new WindowlessLabel("Margin!");
margin.Margin = new Thickness(20, 20, 20, 20); // margins for the left, top, right, and bottom
stack.Controls.Add(margin);

image

As you can see, there is a visible 20 pixel margin along the top and left of the rendered text. Just like any other layout framework, WindowlessControls supports the concept of nested controls: you can place controls within other controls. An entire control group is then subject to the layout of its parent. For example, by creating a centered stack panel and adding two labels to it, all the children of the StackPanel end up being centered:

// nest controls within another control and center the parent
StackPanel child = new StackPanel();
child.Controls.Add(new WindowlessLabel("Nested"));
child.Controls.Add(new WindowlessLabel("Controls"));

image

Now, let's add a Hyperlink into that same StackPanel, and handle it's WindowlessClick event:

// create a clickable hyperlink
HyperlinkButton button = new HyperlinkButton("Click Me!");
child.Controls.Add(button);
button.WindowlessClick += (s, e) =>
    {
        MessageBox.Show("Hello!");
    };

 

image

As shown in the code, the click event is called WindowlessClick as opposed to Click. Click is the standard Windows Forms event, whereas WindowlessClick behaves differently. This is because all WindowlessControls bubble all Control events to every Host in its hierarchy. This means that the WindowlessClick event is also fired and available to be handled on "myHost", the top level control! Let's test this out:

// when the hyperlink is clicked, the event will bubble up to every host in the hierarchy
// watch for the event and handle it
myHost.WindowlessClick += (s, e) =>
    {
        if (s != myHost)
        {
            MessageBox.Show("A click event just bubbled up to me from " + s.GetType().ToString() + "!");
        }
    };
child.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;
stack.Controls.Add(child);

image

Finally, let's draw a centered image on the screen. Grab an image and add it to your project. Set its Build Action to "Embedded Resource" in the properties pane. Then add the following code:

// draw a centered image
PlatformBitmap bitmap = PlatformBitmap.FromResource("mybrainhurts.jpg");
WindowlessImage image = new WindowlessImage(bitmap);
image.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;
stack.Controls.Add(image);

image

Done! Note that PlatformBitmap is different from System.Drawing.Bitmap. The problem with System.Drawing.Bitmap is that it does not support transparencies on Windows Mobile. However, the Imaging API available in Windows Mobile does support images with per pixel alpha. PlatformBitmap provides an abstraction layer around images: they either wrap standard Bitmap objects or they wrap an IBitmapImage from the Imaging API. The PlatformBitmap.Load function will handle that abstraction for you transparently, and choose the appropriate API based on the image type.

Anyhow, I understand this doesn't look that enticing yet, but worry not! Next article, I'll demonstrate the data driven controls and custom/composite controls. That's when things get interesting.

Click here to download the source code for this tutorial.

Quick and Dirty Converter Tool to Create Android Splash Images

g1splash 

An Android splash image is just a 320x480 bitmap in R5G6B5 format. But there is a lack of decent tool that will easily create such a file for you. I wrote one up really quickly to fill that gap. This will perform all the resizing, pixel format conversion, and centering for you. You can also preview the image. Pretty handy.

To flash an image:

  1. Start your phone up in Fastboot mode (you must have the Engineering bootloader). You can do this by holding camera and pressing power. Then connect your phone to your PC. Make sure that it is detected as HTC Dream. If you only see "High Composite Device", you will need to install the Android USB Driver. Then press back until it says "Fastboot".
  2. Convert an image using the tool.
  3. Type the following command: fastboot flash splash1 mysplash.rgb565
  4. Reboot your phone with the command: fastboot reboot

You should now see your new splash screen!

Download for the source code and binaries for the converter.

Fastboot for Windows.

Fastboot for Linux.

Fastboot for Mac OSX.

Building the Android source and Deploying it to your G1 or Dev Phone

mycupcake 

I have no idea why this is not well documented anywhere... I figured most of this out by scouring posts and through trial and error.

This process will create a build of the Android source tree with the Maps application included. Note that this does not have Gmail, YouTube, Market, or IM. These are third party applications to which source is not included. I tried to patch them in, but at the time of writing, their versions were too old to work with the new framework/build. As such, I would not say this is a really usable build by any means.

Installation prerequisites:

  • You must have a rooted (or a dev) phone.

Installation of the provided Android image files (see the end of the post for how to build them manually):
  1. Install the JesusFreke's RC30 V1.3+. This will give you a root shell root access in recovery mode. A root adb shell is required for the next step.
  2. Install the engineering boot loader.
  3. Download the prebuilt cupcake installation images to your computer. Extract them to a folder somewhere. (Note: I will probably not be keeping this image up to date, so you are better of learning how to build from source. See the do-it-yourself instructions at the end.)
  4. Get Fastboot for your computer.
  5. Start your phone up into fastboot mode. You can do this by shutting your phone off, and holding camera and power. You will see Androids on skateboards.
  6. Connect your phone to your computer. Press the back button on your phone until your screen says FASTBOOT.
  7. Go to a terminal on your computer and navigate to your extracted (or built) files and type:
    • chmod a+x fastboot
    • (If you are building from source, make sure the built /out/host/platform/bin directory is in your PATH. Additionally, type "fastboot" rather than "./fastboot")
    • ./fastboot flash system system.img
    • ./fastboot flash boot boot.img
    • ./fastboot flash userdata userdata.img
    • ./fastboot reboot
    • If your phone hangs for a long time while flashing or rebooting, unplug and reconnect your phone. I run into this issue, and that is how I work around it. This may be an issue with the phone being connected to a VM.

Congratulations! You are done!

Reverting Back to the G1/Dev Image

  1. Reflash the modified RC30 image from your SD card. If you start up now, your phone will not start up (it will stay hung at the flashing robot). No big deal though.
  2. Start up in recovery mode (turn on the phone using home and power). Press Alt-L to show the menu, and press Alt-W to wipe the phone.


Do it Yourself Instructions For Building from Source

At the time of writing, the Android Dream build was broken. I needed to do the following to make it work:
  • Several (relatively minor) changes in the Dream audio driver code to fix compilation issues.
  • Copied libOmxCore.so to mydroid/out/target/product/dream/system/lib (this was a missing step in the Building for Dream documentation, and something that should be in the HTC provided script)
Patching in Maps
  1. Copy Maps.apk from a Android Dev Phone 1 into mydroid/out/target/product/dream/system/app
  2. Copy com.google.android.maps.jar from a from a Android Dev Phone 1 into mydroid/out/target/product/dream/system/framework
  3. Delete mydroid\out\target\product\dream\obj\PACKAGING\systemimage_unopt_intermediates\system.img
  4. Delete mydroid\out\target\product\dream\system.img
  5. make

Mono on Android

It's been a little quiet on my blog lately... too quiet. It's cause I've been bashing my head against a wall trying to get Mono on Android (well, Debian running side by side with Android really). So far, I've gotten the Mono runtime cross compiled for Android, but attempting to run anything results in the following:

localhost:~/Desktop/junk# mono
Usage is: mono [options] program [program-options]

Development:
    --aot                  Compiles the assembly to native code
    --debug[=<options>]    Enable debugging support, use --help-debug for details
    --profile[=profiler]   Runs in profiling mode with the specified profiler module
    --trace[=EXPR]         Enable tracing, use --help-trace for details
    --help-devel           Shows more options available to developers

Runtime:
    --config FILE          Loads FILE as the Mono config
    --verbose, -v          Increases the verbosity level
    --help, -h             Show usage information
    --version, -V          Show version information
    --runtime=VERSION      Use the VERSION runtime, instead of autodetecting
    --optimize=OPT         Turns on or off a specific optimization
                           Use --list-opt to get a list of optimizations
    --security[=mode]      Turns on the unsupported security manager (off by default)
                           mode is one of cas, core-clr, verifiable or validil

localhost:~/Desktop/junk# mono test.exe
Illegal instruction

 

Note that mono works fine, but attempting to run a program fails. So yeah, I'm at a loss. I'm guessing there is a bug in the ARM JIT somewhere. Or maybe my make process went horribly wrong due to user error somewhere. I'll try getting Mono from the trunk and building and installing. Apparently there are some more ARM related fixes in there.

I managed to get this far by:

Install Debian on Android.

Cross Compile Mono and its dependency chain using Scratchbox (there are a lot, which I'll detail in a later post). I also did some of the compilation on the G1 itself rather than Scratchbox.

Hyper-V + Aero = Poor System Performance

Just a heads up. I ran into this issue earlier this year while setting up the Hyper-V Release Candidate, and just ran into it again on the RTM version (due to my short memory). If you are using Hyper-V and decide to enable Aero, your host system performance will slow to a complete crawl. Especially while doing anything video or graphics intensive: moving windows, watching movies, opening pictures, etc.

I ended up uninstalling Hyper-V from my desktop and moving the VM to a dedicated Hyper-V server... What can I say? I like Aero.

More information about the Hyper-V performance bug can be found here.

GL Maps goes Open Source

glmaps

GL Maps is a really interesting and fun project, but I haven't had any time to work on it as of late! But I figure that other developers may be interested in carrying the torch. I'll probably return to this project some day in the distant future...

Download GL Maps source code here.

C# 4.0! Visual Studio 2010 CTP!

Can't believe I missed this release... There's a lot of exciting new features upcoming in the .NET front. My personal favorites:

  • IDynamicObject and C# 4.0: C# can now has native/syntactic support for dynamic objects that may come from JavaScript, IronRuby, IronPython, COM, etc. Pretty awesome!
  • Optional Parameters: Remember the good ol' days of C++ where you could define optional parameters with default values set for you? Yeah, they're back. I imagine that some changes had to be made to the type system/reflector; I'm curious as to how this works under the hood.

Click here to download the Visual Studio 2010 and .NET Framework 4.0 CTP.

And here's some documentation and code samples for the new features in C# 4.0.

Note: Ugh, the CTP is a Virtual PC instance. Guess I'll have to wait till they have a installable version, or maybe just convert the instance to HyperV...

Quoted in Business Week

I was interviewed/quoted for an article in Business Week, "Windows Mobile: What Microsoft Needs to Fix". Kinda cool.

The Microsoft/Netflix Marriage - Coming Soon to a Windows Mobile phone near you?

Netflix's Watch Instantly first came to the Windows PC, and then to the Xbox. And, apparently Netflix loves being in bed with Microsoft so much they decided to scrap their existing online movie player in favor of one based on Silverlight. If you want to try the new Beta player, check this link out: http://www.netflix.com/silverlightoptin

How long till we see a player for Windows Mobile? I made an offhand prediction a while ago that we'd see Netflix on Windows Mobile phones within the year. A Silverlight implementation may make it that much more of a reality...

Random Infrastructure Ramblings

Although I've been a little discontent about Windows Mobile development lately, I have nothing but good things to say about Microsoft software products in general. They have the best offerings in desktop and server operating systems, best office productivity applications, infrastructure services, and by far the best development tools.

Conversely, Google provides the best of everything in the way of web related services: maps, email, hosting, browser, blogging, etc.

Around a year or so ago, I decided to (re)purchase koushikdutta.com. I wasn't really sure what I was going to do with it at the time. I just figured that my domain name should probably belong to me. I'd heard some good things about Google Apps hosting services, and decided to try it out. The whole ordeal cost me 10 bucks, so it was a no brainer really.

It took me a few weeks of learning and tinkering to get my infrastructure setup perfect, but I ended up with an infrastructure that I'm very happy with:

  • It can resolve home.koushikdutta.com to a dynamic IP so I can reach my computer from anywhere.
  • Blogger is set up to host my blog on www.koushikdutta.com.
  • All my mail is mirrored between an internal Exchange server and my account Gmail hosted by Google Apps (@koushikdutta.com).
  • ActiveSync and Gmail push to both my Windows Mobile and Android phones.
  • VPN into my home network from anywhere.

 

Hosting a top level Domain from a Dynamic IP

When your router connects to your ISP, it gets a "lease" on an IP. That lease generally expires after a few days, at which point, you may get a different IP. This is called a "dynamic IP". And since the IP is changing fairly regularly, you normally can't associate a domain to it.

For those not in on this little secret, there is a free service called DynDNS that allows you to map a dynamic IP to one of DynDNS's subdomains. With the DynDNS Update Client, your computer can watch for IP changes and report them to DynDNS. DynDNS will then update the IP address of your domain name.

In my case, my router actually supports the DynDNS Service:

dyndns

As you can see, my home network is can be resolved from the internet via clockwork.dyndns.org. So now I have a CNAME that is hooked to a shifty IP. The next step is to have my domain, koushikdutta.com, resolve to clockwork.dyndns.org. By going into the Advanced DNS settings for my Google hosted domain (which is backed by www.enom.com), I set a couple subdomains of koushikdutta.com to resolve to my DynDNS subdomain:

dns.

As you can see, home.koushikdutta.com, mail.koushikdutta.com and clockworks.koushikdutta.com all point to my DynDNS address, which in turn points to my home network.

Remote Desktop is indisposable for me nowadays. Couple that with DynDNS, and I can access my computer remotely from anywhere.

 

Pointing a Domain hosted by Google to a Blog hosted by Blogger

I did not have www.koushikdutta.com or koushikdutta.com resolve to my home IP, because I want them to go to my blog hosted by Blogger. If your domain was purchased through Google Apps, setting it up to play nicely with Blogger is really simple. Just go to your Blogger account settings and click on the Publishing tab to publish to a custom domain:

blogger

 

Gmail and Exchange Integration

Gmail is a pretty fantastic email hosting service. Not really because of the web client, storage space, or any of the other random features. It's great because the spam filter actually works:

Email Account Spam in my Inbox
11.30.08 - 12.06.08
Gmail 0
Hotmail 2
Yahoo! 38

Admittedly, Hotmail isn't that bad either. But for some reason Microsoft decided that standard offerings from other services like IMAP and POP3 access should only be available to people with a Premium Membership.

My goal in this part of the project was a little nonstandard: I wanted to access the same mail via the Gmail interface and also have that email synchronized to my Exchange server. Gmail would provide a 99.9% reliable delivery destination and a trusted SMTP server for handshaking so my emails don't get caught in a spam filters. And Exchange would give me the nicety of being able to access my email through Outlook as well as ActiveSync for my Windows Mobile phones.

So, I first set up Google Apps to provide Gmail service for koushikdutta.com and added the mail accounts:

googleappsmail googleappsaccounts

With that I would have a working Gmail account at koushikdutta.com. Next step was to set up my Exchange server account to accept mail to a couple different addresses:

exchangesetup

Notice that I have an email@clockwork.dyndns.org in that list. This email address alias provides the means of mirroring the Gmail and Exchange accounts. My Gmail account redirects all my mail to this alias:

gmailsettings

Note that this is actually doing a redirect, and not a forward. So when my Exchange server receives it, it thinks that it received an email for email@koushikdutta.com and not email@clockwork.dyndns.org.

The last step is to set up my Exchange server to use Gmail's SMTP servers. This can be done by setting up an Exchange Send Connector that routes mail through a Smart Host (smtp.gmail.com):

exchangesmtpsetup

I could forego this step, but then my mails may end bouncing due to it coming from a unauthenticated source (my personal computer), thus ending up in a Junk Mail folder. And since it is sent through Gmail's SMTP server, the sent emails will also show up in your Sent folder in that account. (Note: Emails sent through the Gmail interface will NOT show up in the Exchange sent items)

Finally, I forwarded my @gmail.com and @hotmail.com mails to @koushikdutta.com. The end result looks something like this:

infrastructure

I get push email from any account to both my phones!

 

VMs, Data Backup, et al.

This isn't really related to this article, but server setup and management is so trivial with Microsoft products. Hate to sound like a zealot, but it's true. Currently, I have one physical machine that hosts 2 Domain Controllers, 1 Exchange Server, and 1 Team Foundation Server (for source control).

hyperv

My biggest concern with this setup was "What happens if my VM host machine dies?". There's no need for SQL replication or some other process that would only back up your data. For this, there is a quick and easy solution. Just mirror the entire disk that hosts the VMs. So if your VM host or any one hard drive crashes, no data is lost, including the state of the machines hosting the services:

diskmirror

Incidentally, my VM host did explode/die a few months ago. It took me around 1 hour to go buy replacement parts from Fry's. And it took me around 10 minutes to transfer the VMs to the new computer I built.

Auto Rotate for the Android Browser

I'm not sure why the Android Browser doesn't auto rotate by default. Instead they have a "Flip Orientation" menu item that lets you toggle your default orientation. Pretty useless overall. Anyhow, a quick hack in the Browser source code let me enable auto rotation via the G-Sensor.

The change is really trivial. In the BrowserActivity.onCreate, I hard coded the orientation to ActivityInfo.SCREEN_ORIENTATION_SENSOR instead of pulling it from a preferences setting.

The downside is that the flip orientation menu item no longer works. Not that I care: I (and probably most people) never used it. So it is a hack, but oh well. If I'm motivated I'll put in a proper fix.

Installation Instructions (you must have root access):

  • Download the updated Browser.apk
  • Run the following from the command prompt to back up your current Browser file to your sdcard and install the new one:
    • adb remount
    • adb pull /system/app/Browser.apk BrowserBackup.apk
    • adb push BrowserBackup.apk /sdcard
    • adb shell rm /system/app/Browser.odex
    • adb push Browser.apk /system/app

Usability Updates for the Android Screenshot Tool

Thanks to some tips and feedback from the folks at xda-developers, I've been able to make some handy changes to the Screenshot application:

  • Screenshots are now captured much faster; images are being decoded directly from the R5G6B5 format.
  • Screenshots are now automatically saved to the SD card.
  • You can now use the camera button to capture screenshots. (The Screenshot application must be started first)
  • If you assign a hotkey to the Screenshot application, you can use that hotkey to also instantly take a screenshot. (The Screenshot application must be started first)