UI Testing for Indie Xamarin Devs

In the Xamarin 4 announcement, there were hundreds of improvements, but some of the most exciting points for indie devs included free access to UITest and Xamarin Insights.

I noticed especially well-received comments during my presentation at the Gauteng Xamarin User Group. Typically South African indie devs complained about high prices, especially due to the exchange rate being very unfavourable.

And this is not just for South Africans; Indie devs don’t usually have large amounts of money to throw at Unit Testing frameworks. They might just grab the best free tool out there. And now, Xamarin has become that “best” and “free” tool.

Xamarin.UITest

I think Xamarin.UITest is the best automated UI testing framework currently available. It takes two tried-and-tested frameworks: NUnit and Calabash and merges them to create a excellent C# API for controlling mobile apps.

Not only does UITest make testing easier, we can also test on both devices and simulators at no additional cost. No extra configuration is needed either. When the project is compiled, the test appear in the IDE’s Unit Test panel. From there, the tests can be run as any other unit test.

I installed the NUnit Test Adapter for Visual Studio as this IDE can’t run NUnit tests natively.

Simple Example

Using UITest is very easy, and just requires that the interaction is described using C# code. The actual flow of the code is the same as if you had actually performed the actions on the device.

Lets take an example test case – making sure a credit card number is valid. We would first want to make sure that the text field is clear before entering the number. Then, after the keyboard is hidden, we want to start the validation. Finally, we need to ensure that the error message appears.

In this test, failure comes if the error message does not appear at all, or if the screen changes.

// clear credit card number
app.ClearText("CreditCardNumber");

// enter a card number
app.EnterText("CreditCardNumber", "123456789123456");

// make sure the keyboard is gone
app.DismissKeyboard();

// tap the validate button
app.Tap (c => c.Button ("ValidateCreditCard"));

// make sure that the error message appears
app.WaitForElement(c => c.Marked("Credit card number is invalid."));

Xamarin Test Recorder

Xamarin recently announced the Xamarin Test Recorder, a preview tool that makes writing mobile UI tests even easier.

Instead of writing this test by hand from scratch, we can make use of the recorder to interact with the app. While we do this, the recorder writes out the steps in C# code. We can then take this code and add it to our test project.

Although the recorder is not perfect yet, we can still use the code and just tweak it a bit. I found that sometimes the recorder wasn’t able to pick up when I had tapped on switches or sliders, but this can be changed. If the element has an ID, then we can swap out the code that tries to find the element by UI index with code that finds the element by ID.

Xamarin 4 – in Bullet Form

With the announcement of Xamarin 4, there were hundreds of changes, new features and improvement. Xamarin included major and minor changes to all phases of the lifecycle of a mobile app.

Mobile Life Cycle

I thought I would re-share some of the features, just in case you missed some :) But, during my presentation at the Gauteng Xamarin User Group, I saw some areas that were especially interesting to South Africa developers.

New in the Xamarin Platform

The most well known area of Xamarin is the BUILD platform. This received some love:

  • Xamarin.Forms 2.0
    Faster, more reliable, and more functional. Pre-compiled XAML. Support for UWP, iOS 9 and Android Material Design. New gestures.
  • Visual Studio and iOS
    Rebuilt the Visual Studio extension from the ground up. Multiple concurrent Visual Studio instances.
  • Mono/.NET Upgrade
    Incorporated large portions from Microsoft’s open sourced .NET codebase.
  • Android and iOS Designers
    iOS designer can load XIB files. Android designer supports Android Material Design. Improved UI and UX for both designers.
  • Objective Sharpie & CocoaPods
    Improved parsing of header files. New attributes for Objective-C equivalents. Support for generating bindings from a CocoaPod.

New in Xamarin Test Cloud

More recently added to Xamarin is the advanced testing capabilities using new testing tools:

  • Xamarin Test Recorder
    New preview tool that makes mobile UI testing dead simple. Initially available for Mac
  • Xamarin.UITest 1.0
    New capabilities for advanced test scenarios. Free for everyone to use. No limits on test duration. No limits on the use of local devices and simulators.

Xamarin Insights

Now generally available, you can track your apps in the wild:

  • General Availability
    Free crash reporting for all Xamarin Platform customers. 30 days data retention.

Something for Everyone

Along with new features and improvements, Xamarin has given developers even more free stuff with each subscription:

  • Xamarin Insights with 30 day data retention.
  • 60 Xamarin Test Cloud device minutes per month.
  • Complete access to Xamarin.UITest.
  • A 30-day trial pass to Xamarin University.

Read the official announcement by Xamarin.

My New (First) Book and This Year

eBook: $40 | Print + eBook: $50

This has been a great year so far, I have released multiple new components on the Xamarin Component Store, committed thousands of lines of code into various repositories, and, finally had my book published!

It has been a long time coming, originally scheduled for about 6 months, but working full time had forced me to go a bit slower. So after 12 months of work, Packt Publishing, made my book, “Xamarin Mobile Development for Android Cookbook”, available to the world.

Beginning Writing

In September last year, they contacted me about authoring a book focused on more advanced concepts when developing Android apps using the Xamarin platform. I cover concepts ranging from using basic UI elements, to managing view states. I also show how one can make use of Bluetooth and NFC communication. Included in the topics are some that cover modern app development, such as making use of the Android support libraries to create modern apps that run on almost all versions of Android.

I won’t lie and say that the book was easy; writing is pretty hard. Once the topic is decided and the code ready, the actual readable text takes a bit of work. I feel that I was able to bring each recipe across in an easy-to-consume manner without compromising on the actual content. This is a lot of work in that it is sometimes hard to write a technical document without knowing the knowledge level of the reader.
In addition to that, sometimes I had to research why I did something. I have done something so many times that it has become automatic, and then I have to go and learn why. And then I sometimes realize that what I had been doing all this time was only one way…

All in all, I quite enjoyed writing, even if it meant very late nights. If I was to write another book, well, it might be some time in the future. I hope that my book sells well, not because of money, but it is an accomplishment. How many people can say they have written a book, and how many of those can say they wrote a good book. If this book sells well, then I would have achieved one of my life goals.

After I first found out about software development when I was 9 years old, I wanted to become a programmer. After the release of Windows, I wanted to be the new Bill Gates. I don’t think I’ll ever get to that level of awesomeness, but I can go for the other things. One of those things is to provide developers with tools that they can use to create the best that can be created.

Why I Started

When I started developing professionally, my projects were ASP.NET websites and Desktop applications. This is great, but typically those apps were company apps and only used during work hours. Mobile apps have always been a passion of mine in that they travel with the user. I have always liked being a back end developer as this is often the area where the “cool” work is done. The UI is great, don’t get me wrong, but almost all of them talk to some library or service.

During my years of development, I really grew to love my work more and more. This love grew into something that I want to share with the world. It started off by helping by brother do a bit of development. He now has built several games using many of the game creation tools. One of the coolest, and most cross-platform, is Scirra’s Construct 2. Recently, he has started using Unity 3D.

Another way I shared my love for development is though my code. I have several repositories on GitHub, which I try and update. I also use this account to update repositories in the community. Sometimes there is that awesome library, but just doesn’t have that feature… For example, there is this tiny library, NLipsum, that allows you to generate a chunk of lorerm ipsum. Although technically not very useful, it is often the simplest way to populate text fields. This library required no changes, but could only be used with desktop .NET platforms. In the age of mobile development, I was able to add a new project that created a Portable Class Library, which can be used everywhere. This is not a headlines-worthy change, but NLipsum is now more cross-platform than ever before.

Writing a book was just another way to share my knowledge and love of development with the world. I hope my book helps both the new guy on the block as well as the other guy that never got around to using In-App billing in his popular Android app. As a result, I am not going to tell you to buy my book… If you want to check it out, or use it to get started with Xamarin.Android apps, you can order it in both an ebook and/or print from Packt Publishing for $32.

Stretching Views with Auto Layout on iOS

I am busy porting my Windows Phone app to Android and iOS, and everything seems to be going quite well. I am using MvvmCross with Xamarin Platform Tools and there is much code reuse.

This is a simple app, literally two screens that could actually be merged into a single screen: A ID number entry form and a status page with a few lines of text. However an app is an app and an Android, iOS and Windows Phone app is still just awesome to have.

This is my first attempt at creating an iOS app from scratch. I have done a couple of Android apps for various companies, but iOS is still ultra new for me. So far as I can see, Apple has created a huge API with many great interfaces. The iOS API is more mature than the Android API, and this shows in many areas.

One of the awesome features that I came across is the Auto Layout features of creating interfaces. My app’s start screen has a view that contains the controls and an image view underneath. The controls view is of a fixed size as it just contains a text box and a button, but the image scaled to fit the remaining space.

On Windows Phone, I was just using a Grid with an expandable row and set the image to fill it. On Android, I placed the image view inside a LinearLayout and set the weight to 1. On iOS, I wasn’t sure… I recalled from my previous dabbling that there was some Autoresizing options, but after reading around, there seems to be something better, Auto Layout.

Eventually, I discovered that this is quite powerful, but a little more complex. What I needed to do was set the image view to be “anchored” at various points. In this case, the image was to expand to fill the space, so I naturally set the top, left bottom and right sides to be pinned at a nice space from the edge of the screen.

I expected the view, if pinned at the top and at the bottom, would grow as the points moved apart, unfortunately for me, there was something that I missed. The height. When I looked around, there was a little icon showing that there was a problem with my constraints. It picked up that there was a problem with the heights of my views, but I wasn’t sure what to do exactly.

My first solution to the problem, but actually wasn’t a solution was to see if there was a way to tell the image view to be expandable. For some reason it did not occur to me that if it was growing horizontally and not vertically, I needed to check to see what was different there. But anyway, I found a little option called “Intrinsic Size” and if I set this to “Placeholder” all the errors went away, but sadly for me, this has little to do with my problem. Intrinsic Size is for when there is shadows or other decoration features that the layout engine should ignore. Even though there were no errors, the actual app on the device just failed and the image was stretched over everything. Sad.

So, it finally occurred to me that if my image was anchored below the controls view, I may actually need to specify a height for the controls. This is not exactly intuitive as it should use the designer’s size automatically, but that’s just me. Anyway, after giving the controls view a height, the running app now correctly stretched my image from the bottom of the view to the bottom of the screen, or, filled the space. Yay!

Because I am cool with images, and Balsamiq Mockups, I have prepared an image for the viewers:

Auto Layout on iOS

Genetics for Xamarin.Android

As with all my development, I try to do as little as possible :) The more code you type, the more you have to maintain and bugfix.

Now, being that I enjoy working on libraries/backends rather than on UI/frontends, I like my code to be neat and clean. Sure, the final app must be good, but I read the code.

So, I looked around and found a simple way to reduce the overall boilerplate code, as well as improve the final code. Although good code doesn’t mean a good app, bad code often results in a poor app.

A Practical Example

This library is focused around only one small things, but that one small thing is done over and over again everywhere… boilerplate! This one thing is getting hold of an Android View or Resource based on the ID.

For example, if we have an Activity with X amount of UI widgets that we need to access:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:padding="8dp">
  <TextView
    android:id="@+id/myLabel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textSize="50sp" />
  <Button
    android:id="@+id/myButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" />
  <ListView
    android:id="@+id/myListView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:layout_margin="10dp" />
</LinearLayout>

Then, usually we would have X number of FindViewById method calls and X fields:

private TextView myLabel;
private Button myButton;
private ListView myListView;

protected override void OnCreate(Bundle savedInstanceState)
{
  base.OnCreate(savedInstanceState);

  SetContentView(Resource.Layout.MyActivityLayout);

  myLabel = this.FindViewById<TextView>(Resource.Id.myLabel);
  myButton = this.FindViewById<Button>(Resource.Id.myButton);
  myListView = this.FindViewById<ListView>(Resource.Id.myListView);
}

This is not much code as it stands, but it is a bit monotonic if you ask me… especially if you have a good few widgets on the screen.

Now, this is where Genetics comes in. We can replace all those FindViewById methods with a single Splice method call, and annotate the fields, or properties, with the [Splice] attribute:

[Splice(Resource.Id.myLabel)]
private TextView myLabel;
[Splice(Resource.Id.myButton)]
private Button myButton;
[Splice(Resource.Id.myListView)]
private ListView myListView;

protected override void OnCreate(Bundle state)
{
  base.OnCreate(state);

  SetContentView(Resource.Layout.MyActivityLayout);

  Geneticist.Splice(this);
}

And that’s all there is to it!

Resources

Not only can we avoid all the FindViewById method calls, but we can also avoid querying the Resources object for the various values. Given the resource file:

<resources> 
  <string name="titleText">Genetics</string> 
</resources>

We can automatically populate the field or property in the same way as with the views.

[Splice(Resource.String.loginError)]
private string loginErrorMessage;

protected override void OnCreate(Bundle state)
{
  // ...

  Geneticist.Splice(this);
}

Fragments

A special case exists when the target object instance that contains the widgets is not an Activity, Dialog or View. This is most commonly used when inflating views, as when using a Fragment:

public class MyFragment : Fragment
{
  [Splice(Resource.Id.textView)]
  private TextView textView;

  public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle state)
  {
    var view = inflater.Inflate(Resource.Layout.MyFragmentLayout, container, false);

    Geneticist.Splice(this, view);

    return view;
  }
}

List Views

Another popular case is when working with a ListView and the view holder pattern for the list items:

public class SimpleAdapter : BaseAdapter
{ 
    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        ViewHolder holder;
        if (convertView != null)
        {
            holder = (ViewHolder)convertView.Tag;
        }
        else
        {
            convertView = inflater.Inflate(Resource.Layout.SimpleListItem, parent, false);
            holder = new ViewHolder(convertView);
            convertView.Tag = holder;
        }

        holder.word.Text = ...;
        holder.length.Text = ...;
        holder.position.Text = ...;

        return convertView;
    }

    private class ViewHolder : Java.Lang.Object
    {
        [Splice(Resource.Id.word)] 
        public TextView word;
        [Splice(Resource.Id.length)] 
        public TextView length;
        [Splice(Resource.Id.position)] 
        public TextView position;

        public ViewHolder(View view)
        {
            Geneticist.Splice(this, view);
        }
    }
}

Downloading & Using

There is lots more that can be done, or rather, not done, using Genetics. The best way to get hold of this library is either through the Xamarin Components Store or from NuGet.

This library is really tiny, and has no dependencies other than Android…

Lots more information can be found on the Getting Started guide as well as in the github.

Self-Signed Certificates and Xamarin.Android

Recently, I had the opportunity to work with Android and self-signed certificates. This is both simple and complex at the same time. In order for Android to be able to handle self-signed certificates, those certificates have to be registered with the SSLSocketFactory.

The HTTP Client

What we will need to do is create a new SSLSocketFactory, and pass that to the HTTP client. In this case, we are using OkHttpClient to communicate over the network. OkHttp is an HTTP+SPDY client for Android applications, and can be found:

Once we have the socket factory, we pass it to the OkHttpClient using the SetSslSocketFactory method:

// get the socket factory
var socketFactory = GetSocketFactory();
// create a new OkHttpClinet 
var client = new OkHttpClient();
// add the socket factory to the client
client.SetSslSocketFactory(socketFactory);
// now we can use the client as usual
Request request = new Request.Builder().Url(&quot;https://&lt;yourserver&gt;&quot;).Build();
Response response = await client.NewCall(request).ExecuteAsync();
var body = await response.Body().StringAsync();

SSL The Socket Factory

In order to create the socket factory, we will need the self-signed certificate. This can be downloaded from the website, or obtained from the source. Then, we must include it in the app. In this instance, I have added it as a raw resource. Loading the certificate into the socket factory consists of a few steps:

  1. Load the certificate out of the resources/assets and into a Certificate instance
  2. Create a new KeyStore instance, and add the Certificate
  3. Create a new TrustManagerFactory instance from the KeyStore
  4. Get the IX509TrustManager from the TrustManagerFactory
  5. Create the new SSLContext, and initialize with the IX509TrustManager
  6. Get the SocketFactory from the SSLContext

Here is the code that does this:

/// &lt;summary&gt;
/// This method returns the configured SSLSocketFactory that contains
/// the self-signed certificate.
/// &lt;/summary&gt;
public static SSLSocketFactory GetSocketFactory()
{
    // Load our certificate from resources (we created this one using OpenSSL and 
    // saved as a .cer using Windows' certlm console)
    var certificateFactory = CertificateFactory.GetInstance(&quot;X.509&quot;);
    Certificate certificate;
    using (var stream = Application.Context.Resources.OpenRawResource(Resource.Raw.selfsigned)) {
      certificate = certificateFactory.GenerateCertificate(stream);
    }

    // Create a KeyStore containing our trusted CAs
    var keyStore = KeyStore.GetInstance(KeyStore.DefaultType);
    keyStore.Load(null, null);
    keyStore.SetCertificateEntry(&quot;ca&quot;, certificate);

    // Create a TrustManager that trusts the CAs in our keystore
    var algorithm = TrustManagerFactory.DefaultAlgorithm;
    var trustManagerFactory = TrustManagerFactory.GetInstance(algorithm);
    trustManagerFactory.Init(keyStore);
    var trustManagers = trustManagerFactory.GetTrustManagers();
    var trustManager = trustManagers[0].JavaCast&lt;IX509TrustManager&gt;(); 

    // Create an SSLContext that uses our TrustManager
    var context = SSLContext.GetInstance(&quot;TLSv1.2&quot;);
    context.Init(null, new ITrustManager[]{ new CompleteX509TrustManager(trustManager) }, null);    

    // return the final socket factory
    return context.SocketFactory;
}

The Trust Manager

Because we are usinmg a custom trust manager with a custom keystore that only contsins the one self-signed certificate, all other certificates will be rejected. To avoid this, we wrap the trust manager in a new trust manager that first tries the default trust manager. Only when the default trust manager fails to verify the certificate, we try the custom trust manager:

/// &lt;summary&gt;
/// This trust manager wraps a custom socket factory and provides a
/// fallback to the default trust manager with the system certificates.
/// This allows the app to communicate not only with a self-signed 
/// server, but also servers with certificates from a CA.
/// &lt;/summary&gt;
public class CompleteX509TrustManager : Java.Lang.Object, IX509TrustManager
{
    private readonly IX509TrustManager defaultTrustManager;
    private readonly IX509TrustManager localTrustManager;

    public CompleteX509TrustManager(IX509TrustManager localTrustManager)
    {
        this.localTrustManager = localTrustManager;

        var algorithm = TrustManagerFactory.DefaultAlgorithm;
        var defaultTrustManagerFactory = TrustManagerFactory.GetInstance(algorithm);
        defaultTrustManagerFactory.Init((KeyStore)null);
        var trustManagers = trustManagerFactory.GetTrustManagers();
        defaultTrustManager = trustManagers[0].JavaCast&lt;IX509TrustManager&gt;();
    }

    public void CheckClientTrusted(X509Certificate[] chain, string authType)
    {
        // we are the client
    }

    public void CheckServerTrusted(X509Certificate[] chain, string authType)
    {
        try {
            defaultTrustManager.CheckServerTrusted(chain, authType);
        } catch (CertificateException) {
            localTrustManager.CheckServerTrusted(chain, authType);
        }
    }

    public X509Certificate[] GetAcceptedIssuers()
    {
        // we are not the server
        return null;
    }
}

Some of the namespaces used are in the Java and Javax namespaces:

using Java.Interop;
using Java.Net;
using Java.Security;
using Java.Security.Cert;
using Javax.Net.Ssl;

Enabling TLS v1.2 on Android 4.2

While I was busy making self-signed certificates work on Android, I had to add support for TLS version 1.2 on Android 4.2. Although it is supported, it is disabled by default.

The SSL Socket Factory

Enabling TLS support is relatively easy in that we just wrap the DefaultSSLSocketFactory in a new SSLSocketFactory, and when a socket is created, we enable all the supported protocols:

private class CompleteSSLSocketFactory : SSLSocketFactory
{
  private readonly SSLSocketFactory innerFactory;

  public CompleteSSLSocketFactory()
  {
    this.innerFactory = HttpsURLConnection.DefaultSSLSocketFactory;
  }

  public override string[] GetDefaultCipherSuites()
  {
    return innerFactory.GetDefaultCipherSuites();
  }

  public override string[] GetSupportedCipherSuites()
  {
    return innerFactory.GetSupportedCipherSuites();
  }

  public override Socket CreateSocket()
  {
    return MakeSocketSafe(innerFactory.CreateSocket());
  }

  public override Socket CreateSocket(Socket s, string host, int port, bool autoClose)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(s, host, port, autoClose));
  }

  public override Socket CreateSocket(string host, int port)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(host, port));
  }

  public override Socket CreateSocket(string host, int port, InetAddress localHost, int localPort)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(host, port, localHost, localPort));
  }

  public override Socket CreateSocket(InetAddress host, int port)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(host, port));
  }

  public override Socket CreateSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(address, port, localAddress, localPort));
  }

  private Socket MakeSocketSafe(Socket socket)
  {
    var sslSocket = socket as SSLSocket;
    if (sslSocket != null) {
      // enable all supported protocols for this socket
      sslSocket.SetEnabledProtocols(sslSocket.GetSupportedProtocols());
      sslSocket.SetEnabledCipherSuites(sslSocket.GetSupportedCipherSuites());
    }
    return socket;
  }
}

The HTTP Client

Now, we just pass an instance of the factory to the client using SetSslSocketFactory. Although, we caould probably create a singleton for the factory:

// create a new OkHttpClinet 
var client = new OkHttpClient();
// only for the older Androids do we do this
if (Android.OS.Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) {
    client.SetSslSocketFactory(new CompleteSSLSocketFactory()); 
}

Microsoft Band SDK for Xamarin.Android

Xamarin and the Microsoft Band

Microsoft finally released an SDK for the Microsoft Band! Yay! The Band is very much designed for health and fitness uses with many sensors. But, it is certainly not limited to health uses. Because we have access to the sensors and can interact with the device, we can use the Band to enhance and extend our app. Working with Band essentially means communicating with the Band from the app installed on the device.

There are 4 main areas that we can interact with the Band:

  1. Reading information from the Sensors
  2. Creating themed app Tiles
  3. Sending Messages to the Band
  4. Theming and Personalizing the Band

The Library and Source Code

The Microsoft Band SDK is still in preview and is available on the official Developer page. When working with Xamarin.Android, we use the component from the Xamarin Component Store.

The binding 4, where you can fork, extend and improve. I will also be looking to create a PCL version that can be used in cross-platform apps, such as those using the Xamarin.Forms framework.

There are currently two demo apps to look at:

  1. Android Feature Demo – demonstrates all the features for Android
  2. Rotating Hand Demo – shows a simple example using the accelerometer (port from Iris Classon)

Getting Started

Before we can do anything with the Band, we need to be able to connect to it. This involves updating the Band and configuring the Xamarin.Android project.

First, we need to make sure that the latest Microsoft Health app is installed on the Android device and the Band updated with the latest firmware (done through the Health app). The Band needs to be paired with the Android device, and, the Health app needs to be synced with the Band.

Next, we need to ensure that we have set up our Xamarin.Android project with permissions to interact with the Band. The minimum supported Android version is 4.2, or level 17.

Finally, we need to make sure that we have permission to communicate with the Band over Bluetooth. This is easy to add using the [UsesPersmission] attributes:

    [assembly: UsesPermission(Android.Manifest.Permission.Bluetooth)]
    [assembly: UsesPermission(Microsoft.Band.BandClientManager.BindBandService)]

Connecting to a Band

Now that we have the Band, the device and the Xamarin.Android project set up, we can start connecting to the Band.

The first thing we want to do is get a list of the Bands paired with the device:

    var bands = BandClientManager.Instance.GetPairedBands();

Then we need to get an instance of IBandClient that will be used to communicate with the Bands:

    var client = BandClientManager.Instance.Create(this, bands[0]);

Once we have the client, we can connect to the actual Band:

    var result = await client.ConnectTaskAsync();
    if (result != ConnectionResult.Ok) {
        // we couldn't connect
    }

When we no longer require a connection to the Band, we can disconnect:

    await client.DisconnectTaskAsync();

Working with Sensors

Working with Microsoft Band Sensors

The main feature of the Band is the many sensors. The sensors that are available to us are the:

  • Accelerometer
    Provides X, Y, and Z acceleration in meters per second squared (m/s²) units.
  • Contact
    Provides a way to let the developer know if someone is currently wearing the device.
  • Distance
    Provides the total distance in centimeters, current speed in centimeters per second (cm/s), current pace in milliseconds per meter (ms/m), and the current pedometer mode (such as walking or running).
  • Gyroscope
    Provides X, Y, and Z angular velocity in degrees per second (°/sec) units.
  • Heart Rate
    Provides the number of beats per minute, also indicates if the heart rate sensor is fully locked onto the wearer’s heart rate.
  • Pedometer
    Provides the total number of steps the wearer has taken.
  • Skin Temperature
    Provides the current skin temperature of the wearer in degrees Celcius.
  • Ultraviolet (UV)
    Provides the current ultraviolet radiation exposure intensity.

Subscribing to sensors has an impact on the Band’s battery life. The use of each sensor requires power draw (some more than others), so we should only subscribe when the data is absolutely needed for our app.

Connecting to the sensors involves a few steps, namely getting hold of the sensor, attaching an event handler and then starting the sensor listener. So first, we want to get hold of a sensor:

    var accelerometer = client.SensorManager.CreateAccelerometerSensor();

Then we want to attach an event handler to the sensor so that we can be notified of updates. This is called from another thread and we need to be able to handle a high volume of events:

    accelerometer.ReadingChanged += (sender, args) => {
        var yReading = args.SensorReading.AccelerationY;
        RunOnUiThread(() => {
            label.Text = yReading;
        });
    };

Finally, we start listening to the sensor. Some sensors (namely the accelerometer and gyroscope) require a listening interval, or sample rate, which could be 16ms, 32ms or 128ms:

    await accelerometer.StartReadingsTaskAsync(SampleRate.Ms16);

When we want to stop listening, all we have to to is call one method:

    await accelerometer.StopReadingsTaskAsync();

Creating App Tiles

Creating App Tiles on the Microsoft Band

Tiles allow us to create app specific experiences on the Band. The Band supports up to 13 separate tiles, and will allow us to create as many tiles as there is space for.

If we want to find out how many tiles we can still create, we can use the TileManager:

    var capacity = await client.TileManager.GetRemainingTileCapacityTaskAsync();

Each tile consists of several properties:

  • a title or name
  • a tile icon
  • a small/badge icon
  • a theme/colour set

Creating App Tiles on the Microsoft Band

The band is required to have an ID (UUID), a title and an icon. If no small icon is provided, notification/badge numbers will not appear on the tile when a message is received. Each tile can have a custom theme, and if none is provided, then the current Band theme will be used.

The Band does not support colour icons, but only white, alpha blended icons. Also, each tile icon must be be 46×46 pixels. The small icon should be 24×24 pixels. Because the Band does not directly support the native Android bitmap, we use the BandIcon type:

    var options = new BitmapFactory.Options();
    options.InScaled = false;
    var icon = await BitmapFactory.DecodeResourceAsync(Resources, Resource.Raw.tile, options)
    var tileIcon = new BandIcon(icon);

If we want to create a new tile, we use the BandTile.Builder:

    var uuid = Java.Util.UUID.RandomUUID();
    var tileName = "My Tile";
    var tile = new BandTile.Builder(uuid, tileName, tileIcon).Build();

We can also set a small icon and a custom theme:

    var tile = new BandTile.Builder(uuid, tileName, tileIcon)
        .SetTileSmallIcon(badgeIcon)
        .SetTheme(BandTheme.TuxedoTheme)
        .Build();

To add a tile to the band, we make use of the TileManager property:

    var success = await client.TileManager.AddTileTaskAsync(this, tile);

Removing a tile is also a single method on the tile manager:

    var success = await client.TileManager.RemoveTileTaskAsync(tile);

We can either pass the tile to the remove method, or we can just use the ID:

    var success = await client.TileManager.RemoveTileTaskAsync(uuid);

If we want to get a list of all the tiles on the device for our app, we can query the tile manager

    var tiles = await client.TileManager.GetTilesTaskAsync();

Sending Messages

We can display a notification for a tile using the NotificationManager property. There are three types of notifications:

  1. Dialogs
    A quick popup that the user can dismiss and the message will not be persisted on the Band. Dialogs have an accompanying single, short vibration.
  2. Messages
    A persistent notification that will remain in the tile. Up to 8 messages can be persisted before the oldest ones are removed to make room. If the tile has a small icon, the number of unread messages will appear on the tile. Messages may also have an accompanying dialog.
  3. Vibrations
    A haptic feedback mechanism that can be used to alert the user to a notification on the Band.

Each dialog consists of several properties:

  • a tile ID
  • a title
  • a body

A message is similar to a dialog, but contains an extra property:

  • a tile ID
  • a title
  • a body
  • a time stamp

To display a dialog, we need the tile ID, the title and a body:

    var title = "My Message";
    var body = "My explanation for the message.";
    await client.NotificationManager.ShowDialogTaskAsync(uuid, title, body);

Displaying messages is very similar, except there are a few extra parameters:

    var date = DateTime.Now;
    await client.NotificationManager.SendMessageTaskAsync(uuid, title, body, date);

If we want a dialog to appear along with the message, we can add an additional parameter:

    await client.NotificationManager.SendMessageTaskAsync(uuid, title, body, date, true);

To cause the Band to vibrate, we can specify a type of vibration:

    VibrationType vibration = ...
    await client.NotificationManager.VibrateTaskAsync(vibration);

Working with Themes

Working with Themes on the Microsoft Band

Using a theme on the devices could be the tile theme or changing the wallpaper. We can customize the Band in three ways:

  1. App Tile Theme
    This theme applies to only the app, and only when the app is open.
  2. Band Theme
    This theme applies to all the tiles and apps on the Band, except where the app has a custom theme. The tile on the Start Strip will use the Band theme, but once the app opens, it will use the app theme.
  3. Me Tile
    This is the background image on the Me tile. This tile is the first, large tile in the Start Strip.

Whether we customize our app tile theme, or the overall theme, we are provided a few, pre-defined themes. These include:

  • CornFlower
  • Cyber
  • Joule
  • Orchard
  • Penguin
  • Storm
  • Tuxedo
  • Violet

There are two parts to a theme, the tile colours and the app colours. The tile colours are:

  • Base
    This is the normal colour of the tile in the Start Strip. This colour is also used for the app’s back/app bar.
  • High Contrast
    This is the colour of the tile when there is a notification available.
  • Lowlight
    This is the colour of the visual feedback, when the user taps the tile or any buttons in the app.

The app colours are:

  • Highlight
    This is the colour of the app’s header text, such as the title in messages or dialogs.
  • Secondary Text
    This is the colour for other informational text in the app, whether the secondary header or date information in messages.
  • Muted
    This is the colour used when displaying notifications when the app is open, such as when a message is received.

When working with themes, we use the PersonalizationManager property. This provides a way to work with the theme or the Me tile background. In order to get the current theme that is set, we use the GetThemeTaskAsync method:

    var theme = await client.PersonalizationManager.GetThemeTaskAsync();

When we want to create a new theme, we can either modify an existing theme, or we can create a new BandTheme instance:

    var theme = new BandTheme {
        BaseColor = ...,
        HighContrastColor = ...,
        LowlightColor = ...,
        HighlightColor = ...,
        SecondaryTextColor = ...,
        MutedColor = ...
    }

Once we have our theme created, or just modified, we can apply it to the entire Band:

    await client.PersonalizationManager.SetThemeTaskAsync(theme);

If we want to use the theme with a single app tile, we must set it during the construction of the tile:

    var tile = new BandTile.Builder(uuid, tileName, tileIcon)
        .SetTileSmallIcon(badgeIcon)
        .SetTheme(theme)
        .Build();

Customizing the Me Tile

One of the first thing the user sees when looking at the Band is the Me tile. This is the first tile on the Start Strip and is where the date lies.

The background image on this tile must be exactly 210×102 pixels and should be in the RGB565 bitmap format. The bitmap instance type used by the API is Android.Graphics.Bitmap, the same type ised by the usual Android widgets.

If we want to access the image already on the Band, we can use the GetMeTileImageTaskAsync method:

    var bitmap = await client.PersonalizationManager.GetMeTileImageTaskAsync();

To set a new image, we use the SetMeTileImageTaskAsync method:

    await client.PersonalizationManager.SetMeTileImageTaskAsync(bitmap);

OneDrive Picker for Android

The picker is the easiest way to browse, select, open and save OneDrive files an Android app with OneDrive.

OneDrive Picker in Action

The source can be found on GitHub and there is a component on the Xamarin Component Store.

Requirements

Before we can access the OneDrive, we will need to get an App ID. Register the app here to get an App ID (Client ID).

The OneDrive picker library is supported at runtime for Android API revision 14 and greater.

The picker requires the OneDrive app to be installed, in order to function. If the OneDrive app is not installed, the user will be prompted to download the app when either the StartPicking() or StartSaving() method is invoked.

Opening files

Our app needs to give the user a way to start opening files from OneDrive. Here we set up a click handler that launches the open picker:

    // keep a reference to the picker
    private IPicker picker;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // ...

        // create a picker
        picker = Picker.CreatePicker("ONEDRIVE_APP_ID");

        button.Click += delegate {
            // start the picker activity
            picker.StartPicking(this, LinkType.DownloadLink);
        };
    }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        // get the results from the picker activity
        var result = picker.GetPickerResult(requestCode, resultCode, data);
        if (result != null) {
            // use the result
        } else {
            // continue as normal
            base.OnActivityResult(requestCode, resultCode, data);
        }
    }

Start Picking

The picker can be configured to return a URL for the selected file in one of these
formats:

  • LinkType.DownloadLink – the URL is valid for 1 hour and can be used to download a file
  • LinkType.WebViewLink – the readonly URL is valid until the user deletes the sharing link

Picker Result Object

In addition to the filename and link for the file, you can access several other properties on the IPickerResult object that provide more details about the file selected:

    public interface IPickerResult
    {
        Uri Link { get; }
        LinkType LinkType { get; }
        string Name { get; }
        long Size { get; }
        // keys: "small", "medium", and "large"
        IDictionary<string, Uri> ThumbnailLinks { get; }
    }

Saving Files

Similar to when opening files, we should provide a way for the user to save a file to OneDrive. Before we can upload a file, we need a filename for OneDrive and the path to the file on the local file system:

    private ISaver saver;

    protected override void OnCreate (Bundle savedInstanceState)
    {
        base.OnCreate (savedInstanceState);

        // ...

        // create the saver
        saver = Saver.createSaver("ONEDRIVE_APP_ID");

        button.Click += delegate {
            // launch the saver
            saver.startSaving(this, "FILENAME", "file://PATH/TO/FILE");
        }
    };

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        try {
            // the file saved successfully
            saver.HandleSave (requestCode, resultCode, data);
        } catch (SaverException ex) {
            // there was an error
        }
    }

Start Saving

The saver currently supports the content:// and file:// file URI scheme. If a different URI scheme is used, the saver will return a NoFileSpecified error type.

Saver Result

The error message provided by DebugErrorInfo is primarily for development and debugging and can change at any time. When handling errors, you can use ErrorType to determine the general cause of the error.

Saver Error Types

When the saver is unable to complete saving a file and throws an exception, it provides a SaverError through the ErrorType property that indicates one of a set of possible error types:

    public enum SaverError {
        Unknown,
        Cancelled,
        // The OneDrive account did not have enough space
        OutOfQuota,
        InvalidFileName,
        NoNetworkConnectivity,
        // The Uri to the file could not be accessed
        CouldNotAccessFile,
        // No file was specified to be saved, 
        // or the file URI scheme was not supported
        NoFileSpecified
    }

HttpClient and Xamarin.iOS Unified

I was creating a NuGet that was dependent on several other NuGets, one of them being Microsoft.Net.Http. This brings in the great HttpClient for all platforms.

However, there is a small problem right now: Microsoft has not yet updated their NuGet to support Xamarin.iOS Unified. They are working on it, but in the meantime what can we do to still create a NuGet that relies on HttpClient?

Well, we don’t actually need the Microsoft.Net.Http NuGet on the Xamarin platforms as the HttpClient type comes with the actual framework. This is because the Xamarin platforms target the 4.5 version of .NET.

So, we can update our .nuspec to exclude these NuGet dependencies on the Xamarin platforms. If our current .nuspec is similar to this:

<dependencies>
    <dependency id="Microsoft.Bcl" version="1.1.9" />
    <dependency id="Microsoft.Bcl.Build" version="1.0.14" />
    <dependency id="Microsoft.Bcl.Compression" version="3.9.85" />
    <dependency id="Microsoft.Net.Http" version="2.2.28" />
    <dependency id="Rx-Core" version="2.2.5" />
    <dependency id="Rx-Interfaces" version="2.2.5" />
    <dependency id="Rx-Linq" version="2.2.5" />
    <dependency id="Rx-Main" version="2.2.5" />
    <dependency id="Rx-PlatformServices" version="2.2.5" />
</dependencies>

All we have to do is move it into a general “ and add a specific group to the offending Xamarin.iOS platform:

<dependencies>
    <!-- for all platforms -->
    <group>
        <dependency id="Microsoft.Bcl" version="1.1.9" />
        <dependency id="Microsoft.Bcl.Build" version="1.0.14" />
        <dependency id="Microsoft.Bcl.Compression" version="3.9.85" />
        <dependency id="Microsoft.Net.Http" version="2.2.28" />
        <dependency id="Rx-Core" version="2.2.5" />
        <dependency id="Rx-Interfaces" version="2.2.5" />
        <dependency id="Rx-Linq" version="2.2.5" />
        <dependency id="Rx-Main" version="2.2.5" />
        <dependency id="Rx-PlatformServices" version="2.2.5" />
    </group>
    <!-- no Microsoft on iOS Unified -->
    <group targetFramework="XamariniOS1.0">
        <dependency id="Rx-Core" version="2.2.5" />
        <dependency id="Rx-Interfaces" version="2.2.5" />
        <dependency id="Rx-Linq" version="2.2.5" />
        <dependency id="Rx-Main" version="2.2.5" />
        <dependency id="Rx-PlatformServices" version="2.2.5" />
    </group>
</dependencies>

This works, as NuGet will use the more specific for Xamarin.iOS, but fall back to the empty for all other platforms. We can use this mechanism for all platforms. We can even use this for the various files as well. In fact, this is how Microsoft does it now: They include everything for all platforms, and then exclude the specific ones that already have HttpClient built in.

When Microsoft updates their NuGet, all we need to do is drop the “ group from the .nuspec and everything is back to normal.