Surface 2 RT review

First, full disclosure. Late last year, I entered a twitter contest being held by the official Microsoft Surface twitter account, @surface. I had to tweet what I would do if I won a Surface 2 with Surface Music Kit. My answer was somewhat throwaway; a spur of the moment thing:

A few weeks later, I received a DM informing me that I had won "something" and to provide my address within five days. I obliged, expecting to get a t-shirt or some other Surface-related swag; I was incredibly surprised when I received a shipping notification one Tuesday that showed a Surface 2 RT with Surface Music Kit would be arriving that afternoon. That said, there was no requirement on my part to provide a review nor that any such review should be unduly positive. With all that known, please read on.

Surface Music Kit

Surface Music Kit Cover and App
Surface Music Kit Cover and App

Keyboard

One of the cool things about the Microsoft Surface devices are their covers. The covers (available in touch and type variants) have an integrated input device and are the primary method of providing an external keyboard to a Surface1, though one could also use a Bluetooth or USB keyboard. Most of these covers have an embedded QWERTY keyboard and touchpad, much like a small laptop keyboard. However, the Surface Music Kit includes a special keyboard/cover designed for use with the Surface Music Kit application. This cover has three touch sliders (like electronic volume controls), some playback/record controls like one might find in a multimedia playback device, and a grid of 16 pads. Together, these can be used to mix and manipulate samples in the Surface Music Kit application2.

Surface Music Kit cover
Surface Music Kit cover; try typing your password on this
Back-lit Surface Type Cover 2
Back-lit Surface Type Cover 2

Since the device I won came with the music kit cover, my initial problems stemmed from having to use the onscreen keyboard. As cool as the Surface Music Kit is,  I can't type my email password with volume sliders and drum pads. Even though the onscreen keyboard is responsive and has a nice array of layout options (the thumb-friendly layout that splits the keyboard for easy thumb typing is great), I found it a little frustrating to use. Whichever layout I tried, the keyboard occupied too much of the screen, didn't provide the kind of tactile feedback I rely on when typing, and just wasn't fast enough when I wanted to unlock my device. These problems aren't unique to the Surface; I've yet to find any device where the onscreen keyboard doesn't suffer from these problems (though your mileage may vary). Of course, this problem is easily resolved: I received the Type Cover 2 as a Christmas gift from my wife.

Apps

By now, the number of apps in the Windows Store, especially when compared with equivalent Android or Apple stores, has been discussed to death. The Windows Store is getting more apps every day but the choices are limited by comparison with its competitors. That said, all the apps I really wanted such as Netflix, LastPass, and Mouse Without Borders were available and more often than not, other apps had an online equivalent (for example, I can watch Amazon Prime via the website, though it's not all roses when it comes to websites so read on).

The frustrating part of apps running on the Surface RT comes from the desktop. Surface RT devices run a version of Windows built for ARM processors instead of the usual x86/x64 processors that other Windows-based devices use. This means that unless a desktop application has been specifically written to run on this special ARM-based version of Windows (such as Office 2013, which Microsoft provides with the Surface 2 RT) it won't. The outcome of this is that even little apps that you find useful in every day stuff – especially as a developer such as git, node, Sublime, etc. – will not work. I didn't expect to find this as frustrating as I have and it has only been exacerbated with the unnecessary neglect of Internet Explorer by many websites.

Internet Explorer

Internet Explorer 11 is fantastic but also the only option on the Surface 2 RT given that other browsers are not available for the ARM-based platform. In the past, Internet Explorer has had a much-deserved stigma attached to it due to lack of standards compliance, quirky behavior, and poor performance. This has made it difficult for websites to support older versions of IE. However, the Internet Explorer of old is dead and in more recent releases, this stigma is just undeserved dead weight that needs to be cast aside. Unfortunately, this message has either not reached many developers or landed on deaf ears, leading to heavy-handed checks for IE on many sites that block IE users from getting a fully-featured site or interacting with a site at all, even though the site would work if that block were lifted.

As a developer, this has been doubly frustrating. I can't install useful tools like Git or Sublime, nor can I use many online development environments as they don't work or completely block their use from any version of Internet Explorer. This limited browsing experience isn't limited to development tools though; I have found that quite a few sites do not properly support IE. Perhaps one day, Microsoft will convince people that IE should be embraced once more and that its legacy should be left in the past, but until then, users of Surface 2 RT may face a substandard browsing experience.

That said, when sites do work with IE11, they work really well. A standout website for developers has to be Codio. I set this up against my GitHub account and have used it successfully to work on code samples for blog entries. Hopefully more sites begin to support IE like this.

Battery Life and Performance

This is where I should pull up some metrics of how the battery life is for various every day scenarios, but I'm not good at capturing metrics, so I'll tell you my experience. The battery life seems good when using the Surface for general stuff like editing documents, browsing the Internet, etc. The main complaint I have is that I'd like it to have an opt-in auto shutdown if left on sleep for more than a day. While sleep uses very little battery, there are times when my Surface has been sleeping for days on end, resulting in a drained battery. This has led to me shutting down the Surface 2 RT whenever I stop using it, which means I lose out on the "always on"-ness. Although the Surface 2 RT cold boots pretty quickly, the readiness after sleep is significantly faster. That said, I have no substantial complaints; my Surface 2 RT is definitely the most battery-efficient Windows-device I have had so far3.

Other bits and bobs

Front camera, start button and rear camera
Front camera, start button and rear camera

The two cameras on the Surface 2 RT: one front-facing and one rear-facing, stereo speakers and built-in microphone are all excellent and it was a pleasure using all these to give a Skype tour of our new bathroom to my parents back in England. The built-in kickstand with two viewing angle positions is also fantastic. In addition, the Surface 2 RT has a full-size USB port, 3.5mm headphone jack, mini-HDMI port, and microSD slot.

Surface inputs and outputs
Surface inputs and outputs

Service

It is not often that one gets the opportunity to review the quality of device service and repair at the same time as reviewing the device. However, it has been some time since I first received my Surface 2 RT and in that time, I had the misfortune of dropping it on the concrete floor of our basement4. While the Surface 2 RT took the fall with grace, it fumbled the landing, which shattered the screen rendering touch operation impossible.

I followed the instructions on the Surface Online Service Center site to register my device and submit a service request. A broken screen is not covered by the standard warranty, so I paid a $200 fee and got myself a return to print out. I then detached my keyboard and removed the microSD card I had inserted5, and took my broken device to the local FedEx shipment center along with my return information. The packing and shipping of the device was included without any additional charge.

I do not recall just how long the service took, but within a week or two, a refurbished Surface 2 RT arrived on my doorstep. I eagerly unpacked it and turned it on. It sat in a reboot cycle.

I was not happy.

I plugged in the power and tried again. Still stuck in a reboot cycle.

Eventually, I found instructions to do a full factory reset, after which, the device booted but clearly had problems. It was not until after I had downloaded and installed just over one gigabyte of updates that it started to behave properly. It is because of this that I have mixed feelings about the service experience.

On the one hand, it was easy to register my device, submit a service request, and get it shipped. On the other hand, I had to use quite a bit of technical know-how to get the replacement device to work. I feel that if Microsoft wants to win over the non-tech market with these devices, they are going to need to do a lot better. I know for sure that many of my friends and relatives would not have known what to do next if faced with the reboot cycle, probably leading to endless tech support calls to Microsoft, or worse, me.

Conclusion

I have been using my Surface on and off over the last few months. Trying to see where it fits in my life between the eight core desktop PC at home, my core i7 ultrabook at work, and my phone, I was unsure that a tablet/laptop hybrid would work out and to begin with, it did not. However, once I got the QWERTY type cover and discovered which scenarios were useful to me, the Surface 2 RT has been a great addition to my regular arsenal of gadgets6.

The service experience was disappointing. While initially wonderfully easy, it became terribly frustrating once a replacement device was received, especially since I had paid $200 for the privilege. Microsoft needs to pay more attention to detail in this process if it is to become a first class experience.

Overall, I like the Surface 2 RT and will continue to use it (in fact, I have been writing most of this blog using it). However, I have to ask myself if I would have bought one and if I'm honest, I would not. Not because it isn't a great device but because the price tag, like most slates/tablets7, seems high for what you get8.  Of course, that also means I wouldn't buy a competitor's device either so read into that what you will.

  1. both have a track pad, but the type cover has more traditional, plastic backlit keys []
  2. Unfortunately, there is no SDK for using the Surface Music Kit cover in your own apps, which seems like an oversight to me []
  3. I currently use a Windows-based Core i7 ultrabook, but have had a Nokia Windows Phone and a variety of Dell laptops []
  4. It was during a jam session and I was trying to balance it so I could see the lyrics while I played guitar – the Surface was eager to prove that I was stretching myself beyond operating parameters []
  5. Specific instructions stated that these were  not guaranteed to be returned if I left them with the Surface []
  6. desktop, laptop, Android phone, xbox 360, xbox one []
  7. delete as applicable []
  8. clearly, I would've paid $200 for it, considering I was happy to pay that for the repairs []

CodeMash 2.0.1.4

Adventure

It is almost nine years since I first set foot in the US. It was through that experience that I rediscovered the joy in challenging myself and embracing change, something I had not so strongly felt since I first started singing in a band. So, while I had faced challenges before as a result of my own decisions, none had been bigger. Even though the opportunity had been provided by someone else, it had been my choice to take it and to see it through1.

It took me a while to settle in to my new home (or even to acknowledge it as home), but I eventually joined the developer community in Ann Arbor and the wider mid-west region. The interaction with other developers has continued to provide challenging opportunities and encourage positive change within my career, as well other aspects of my life. It was through the basic act of attending one local Ann Arbor .NET Developers Group meeting and the people I met there that I learned about CodeMash.

CodeMash

CodeMash v2.0.1.4 logo
 
The CodeMash conference – a community-organized event held annually in Sandusky, Ohio – never fails to provide unique experiences or challenges. My first CodeMash, CodeMash v2.0.1.2 was unique because I had never attended a developer conference before (or any other conference), and CodeMash v2.0.1.3 provided a completely new experience when, after attending a fantastic workshop on public speaking, I went on to win the PechaKucha contest.

This year, I was guaranteed yet another unique experience when I was accepted to be a speaker. I am extremely grateful to friends, mentors and others for their support and encouragement leading up to speaking at CodeMash v2.0.14. It was a wonderful honor that I thoroughly enjoyed, and while it changed my CodeMash experience with the added anxiety of speaking and subsequent release when my session ended, I would definitely do it again if the chance arose.

To those that attended my talk on AngularJS for XAML developers, thank you. I  hope that you found it valuable. If you were there or if you have an interest, you can find my slide deck and code on GitHub (Deck|Code).

I am very grateful to the volunteers that organize and run CodeMash each year, as well as the many friends and mentors that have guided my own CodeMash experiences and the many other experiences within the developer community. Without these people, I would not have had such amazing opportunities, nor would I have learned how important it is to challenge myself and strive for new experiences. It is always uncomfortable to embrace change, but the rewards of doing so are often worth the pain.

To close, I encourage you to challenge yourself this year. Make sure to let me know in the comments below how you will challenge yourself and perhaps we can follow-up at the end of the year.

  1. Of course, there were many times in the weeks between being offered the position and setting foot in the US when I considered changing my mind, including just after the plane doors closed []

Git integration for all your PowerShells with Github for Windows

We use git for our source control at work. In fact, we use Github. I have GitHub for Windows (GfW) installed because it's one of the easiest ways to install git on a Windows desktop. As part of the installation, you get to choose how the git shell is provided; I selected PowerShell (PS). This works well. You can access the integrated console via a separate shortcut or by the ~ key when viewing a repository in GfW.

However, the git integration (provided by posh-git) isn't available in the standard PS console nor PS ISE1. I use PS ISE a lot more these days as it gives me tabbed console windows and some cool features like auto-complete dropdowns2, so I wanted git integration there too.

As I already have git and posh-git installed via GfW, I didn't want to install both separately again just to get this support, I wanted to use what was already there.

To do this, open your PS or PS ISE console (you'll need to do this for both as they have separate profiles) and enter:

notepad $profile

Then add the following lines and save:

# Load github shell and posh-git example profile
. (Resolve-Path "$env:LOCALAPPDATA\GitHub\shell.ps1")
. (Resolve-Path "$env:github_posh_git\profile.example.ps1")

To see the changes, you need to restart your console. If you're sure there'll be no nasty side-effects from running your profile twice in one session, you could also just enter:

. $profile

And there you have it, git support using the GitHub for Windows installation in all your PowerShell windows.

  1. Integrated Scripting Environment []
  2. There are some caveats to using the ISE console tab over a regular PS console []

SettingsFlyout Class For C#/XAML Windows 8 Apps

One of the interesting things about Windows 8 Modern UI app development is the amount of boilerplate code that the project wizard adds to your project. Why some of the classes are not part of the WinRT base class library is not clear and not hugely important. It is more puzzling to think of the things that are not provided such as a settings flyout wrapper. If you're new to all this, the settings flyout1 is that thing that appears to the right when you use the Settings charm2. Windows has its own implementation for the system level Settings but your app must implement this for its own settings.

I discovered the hard way that to get certified in the Windows Store you must support the settings contract so you can provide "about" information. Adding this isn't particularly difficult, but there is a lot of boilerplate that can be abstracted away. Not only that, but if you're using the WebView, you need to know when the settings come and go to ensure the WebView is properly hidden as it would otherwise draw all over your beautiful settings (I'll perhaps talk about XAML apps and the WebView another time, when I've calmed down a bit).

To simplify this I wrote SettingsFlyout, a simple wrapper that handles the boilerplate activity of showing a UserControl as your settings while providing some handy events to track any settings flyout being shown or hidden. You may notice that other than the dimensions of this flyout, it could easily be adapted to support any of your flyout needs. However, I'm not sure that there are many valid reasons for flyout usage in Modern UI apps other than the standard system implementations and settings. Therefore, I'll leave that up to you, I'd hate to lead you into bad habits.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;

namespace SomewhatAbstract
{
    /// <summary>
    /// Provides a wrapper for showing settings with events to track any settings flyout coming or going.
    /// </summary>
    public class SettingsFlyout
    {
        private const int FlyoutWidth = 346;
        private Popup popup;

        /// <summary>
        /// Shows the given control in the flyout.
        /// </summary>
        public void ShowFlyout(UserControl control)
        {
            this.popup = new Popup();
            this.popup.Opened += OnPopupOpened;
            this.popup.Closed += OnPopupClosed;
            Window.Current.Activated += OnWindowActivated;
            this.popup.IsLightDismissEnabled = true;
            this.popup.Width = FlyoutWidth;
            this.popup.Height = Window.Current.Bounds.Height;

            control.Width = FlyoutWidth;
            control.Height = Window.Current.Bounds.Height;

            this.popup.Child = control;
            this.popup.SetValue(Canvas.LeftProperty, Window.Current.Bounds.Width - FlyoutWidth);
            this.popup.SetValue(Canvas.TopProperty, 0);
            this.popup.IsOpen = true;
        }


        private void OnWindowActivated(object sender, Windows.UI.Core.WindowActivatedEventArgs e)
        {
            if (e.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.Deactivated)
            {
                this.popup.IsOpen = false;
            }
        }

        private void OnPopupClosed(object sender, object e)
        {
            Window.Current.Activated -= OnWindowActivated;
            OnSettingsClosed(EventArgs.Empty);
        }

        private void OnPopupOpened(object sender, object e)
        {
            OnSettingsOpened(EventArgs.Empty);
        }

        /// <summary>
        /// Raised to indicate settings flyout has been opened.
        /// </summary>
        public static event EventHandler SettingsOpened;
        private static void OnSettingsOpened(EventArgs args)
        {
            var handler = SettingsFlyout.SettingsOpened;
            if (handler != null)
            {
                handler(null, args);
            }
        }

        /// <summary>
        /// Raised to indicate settings flyout has been closed.
        /// </summary>
        public static event EventHandler SettingsClosed;
        private static void OnSettingsClosed(EventArgs args)
        {
            var handler = SettingsFlyout.SettingsClosed;
            if (handler != null)
            {
                handler(null, args);
            }
        }
    }
}

Using the SettingsFlyout class is as simple as this:

// Add an About command
var about = new SettingsCommand("about", "About", (handler) =>
{
    var settings = new SettingsFlyout();
    settings.ShowFlyout(new MyAboutSettingsControl());
});

If you find this useful or you did something similar yourself, I would love to hear about it. Is there something you feel is missing that should be there either in WinRT or the project template? Have you created any useful utility classes like this that could be used in almost every app?

  1. A flyout is the new Windows 8 modern UI term for what we might've called a popup, dialog or tooltip in the past. It's anything that appears over your application and you use a Popup control to show them as you would in Silverlight or WPF. []
  2. The Settings charm is the cog-like button that appears when you swipe from the right or hover your mouse in the lower right (or press Windows+C). It looks a lot like an icon, except it's not. It's a charm. []

When the clipboard says, "No!"

Cut, Crash, Paste

I was recently investigating an annoying bug with my WPF DataGrid. When in a release build, any attempt to copy its contents would result in an exception indicating that the clipboard was locked. The C in Ctrl+C stood for Crash instead of Copy. This is a big usability issue. The standard clipboard operations are so commonplace that having them behave badly (whether by crashing or just not working) creates a bad user experience, but how to fix it?

Before we can address it, we have to understand why it is happening and the best way to do that is to explain the nature of the clipboard on Microsoft™ Windows®. On Windows, the clipboard is a shared resource. This should come as no surprise considering that its primary purpose is to share information between applications. Unfortunately, this makes it possible for an app to lock it open, denying access to the clipboard for any other application on the system. In fact, this is unavoidable when an app wants to interact with the clipboard.

Mitigation

Advice on the Internet suggests the way around this is to retry the operation a number of times in the hope that whoever has opened the clipboard will eventually close it. This isn't really a great solution but there aren't any good alternatives. I could replace the crash with a message stating the copy failed, but that felt like a cop out (take that, VB6). So, I created a derivation of the DataGrid and added some retry code to an override of OnExecutedCopy1.

protected override void OnExecutedCopy(
    System.Windows.Input.ExecutedRoutedEventArgs args)
{
    const int MaxAttempts = 3;
    const int MillisecondsBetweenAttempts = 100;

    int attempts = 0;
    while (attempts <= 0 && attempts > MaxAttempts)
    {
        try
        {
            base.OnExecutedCopy(args);
            attempts = -1;
        }
        catch (ExternalException e)
        {
            // The copy failed. Increment our attempt count.
            attempts++;

            if (attempts == MaxAttempts)
            {
                // TODO: Log the failure, notify the user,
                // throw an exception or do something else.
                // Whatever is appropriate to your app.
            }
            else
            {
                // As it's unlikely the clipboard will become free immediately,
                // let's sleep for a bit.
                Thread.Sleep(MillisecondsBetweenAttempts);
            }
        }
    }
}

With something in place to mitigate the issue, it was time to test it. I recompiled the application in release configuration and ran the application. The problem could no longer be reproduced. Success! Right?

Wrong. A breakpoint showed that the first copy attempt wasn't failing anymore. The bug had gone away. Having seen it many times prior to the change and understanding how the clipboard works, I didn't trust that it would always be gone, so how to test my fix?

Using the ClipboardLock, that's how.

What's the ClipboardLock?

Great question! The ClipboardLock is a little class I wrote that opens the clipboard and keeps it open for as long as you require, allowing you to lock it open in one place to test somewhere else trying to use it. I've included it below. Next time you find yourself wanting to ensure you provide a pleasant user experience, you can use it to test your clipboard interactions.

Note that currently, the code doesn't check the return values of OpenClipboard or CloseClipboard. This means that it, itself is susceptible to these calls failing. Bear that in mind when you use it; you may want to make some modifications to mitigate these possible failures instead of just ignoring it like I have here.

public class ClipboardLock : IDisposable
{
    private static class NativeMethods
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public extern static bool OpenClipboard(IntPtr hWnd);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public extern static bool CloseClipboard();
    }

    public ClipboardLock() : this(null)
    {
    }

    public ClipboardLock(IntPtr windowHandle)
    {
        NativeMethods.OpenClipboard(windowHandle);
    }

    ~ClipboardLock()
    {
        Dispose(false);
    }

    private bool disposed;
    private void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            this.disposed = true;

            if (disposing)
            {
            }

            // Free up native resources here.
            NativeMethods.CloseClipboard();
        }
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion
}
  1. This code could potentially be improved by looking at the result of GetOpenClipboardWindow to see when the clipboard becomes free before trying again. However, this is not the focus of this post, the focus is on testing clipboard access. []