しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin.Forms で Microsoft Band のバージョン情報を取得する

接続には成功したものの・・・本当に接続できているのかよくわからず

というわけで接続確認もかねて、接続した Microsoft Band のハードウェアとファームウェアのバージョンを取得してみます

ソースコードの一式は下記にあります!

github.com

※ 順次改修していく予定なので、この記事の内容が現時点のソースより古い可能性があります

Band SDK にはバージョン情報取得用のインターフェースとして IBandClient があるので、こちらを各プラットフォームで実装します

/// <summary>
/// Android 用 Microsoft Band デバイス情報のインターフェース
/// </summary>
public class NativeBandClient : IBandClient
{
    /// <summary>
    /// 接続クライアント
    /// </summary>
    private Native.IBandClient client = null;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="client">接続クライアント</param>
    public NativeBandClient(Native.IBandClient client)
    {
        this.client = client;
    }

    /// <summary>
    /// ファームウェアバージョンを取得する
    /// </summary>
    /// <returns>ファームウェアバージョン</returns>
    public Task<string> GetFirmwareVersionAsync()
    {
        return Native.BandClientExtensions.GetFirmwareVersionTaskAsync(this.client);
    }

    /// <summary>
    /// ファームウェアバージョンを取得する
    /// </summary>
    /// <param name="token">中断トークン</param>
    /// <returns>ファームウェアバージョン</returns>
    [Obsolete("CancellationToken is not supported for Android.")]
    public Task<string> GetFirmwareVersionAsync(CancellationToken token)
    {
        return this.GetFirmwareVersionAsync();
    }

    /// <summary>
    /// ハードウェアバージョンを取得する
    /// </summary>
    /// <returns>ハードウェアバージョン</returns>
    public Task<string> GetHardwareVersionAsync()
    {
        return Native.BandClientExtensions.GetHardwareVersionTaskAsync(this.client);
    }

    /// <summary>
    /// ハードウェアバージョンを取得する
    /// </summary>
    /// <param name="token">中断トークン</param>
    /// <returns>ハードウェアバージョン</returns>
    [Obsolete("CancellationToken is not supported for Android.")]
    public Task<string> GetHardwareVersionAsync(CancellationToken token)
    {
        return this.GetHardwareVersionAsync();
    }

    //TODO:後で実装予定

    public IBandNotificationManager NotificationManager
    {
        get { throw new NotImplementedException(); }
    }

    public IBandPersonalizationManager PersonalizationManager
    {
        get { throw new NotImplementedException(); }
    }

    public IBandSensorManager SensorManager
    {
        get { throw new NotImplementedException(); }
    }

    public IBandTileManager TileManager
    {
        get { throw new NotImplementedException(); }
    }

    public void Dispose()
    {
    }
}

これが Android・・・とりあえずバージョン情報以外は実装保留

中断トークンが使えない!・・・これはしかたがないので、Obsolete 属性をつけて非推奨メソッドにしています

一応たたけるけど機能しないよ!というような扱いです

/// <summary>
/// iOS 用 Microsoft Band デバイス情報のインターフェース
/// </summary>
public class NativeBandClient : IBandClient
{
    /// <summary>
    /// 接続クライアント
    /// </summary>
    private Native.BandClient client = null;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="client">接続クライアント</param>
    public NativeBandClient(Native.BandClient client)
    {
        this.client = client;
    }

    /// <summary>
    /// ファームウェアバージョンを取得する
    /// </summary>
    /// <returns>ファームウェアバージョン</returns>
    public async Task<string> GetFirmwareVersionAsync()
    {
        NSString version = await this.client.GetFirmwareVersionAsyncAsync();
        return version != null ? version.ToString() : string.Empty;
    }

    /// <summary>
    /// ファームウェアバージョンを取得する
    /// </summary>
    /// <param name="token">中断トークン</param>
    /// <returns>ファームウェアバージョン</returns>
    [Obsolete("CancellationToken is not supported for iOS.")]
    public Task<string> GetFirmwareVersionAsync(CancellationToken token)
    {
        return this.GetFirmwareVersionAsync();
    }

    /// <summary>
    /// ハードウェアバージョンを取得する
    /// </summary>
    /// <returns>ハードウェアバージョン</returns>
    public async Task<string> GetHardwareVersionAsync()
    {
        NSString version = await this.client.GetHardwareVersionAsycAsync();
        return version != null ? version.ToString() : string.Empty;
    }

    /// <summary>
    /// ハードウェアバージョンを取得する
    /// </summary>
    /// <param name="token">中断トークン</param>
    /// <returns>ハードウェアバージョン</returns>
    [Obsolete("CancellationToken is not supported for iOS.")]
    public Task<string> GetHardwareVersionAsync(CancellationToken token)
    {
        return this.GetHardwareVersionAsync();
    }

    //TODO:後で実装予定

    public IBandNotificationManager NotificationManager
    {
        get { throw new NotImplementedException(); }
    }

    public IBandPersonalizationManager PersonalizationManager
    {
        get { throw new NotImplementedException(); }
    }

    public IBandSensorManager SensorManager
    {
        get { throw new NotImplementedException(); }
    }

    public IBandTileManager TileManager
    {
        get { throw new NotImplementedException(); }
    }

    public void Dispose()
    {
    }
}

こっちが iOS・・・iOS は string ではなく NSString を返却してきます

string に変換する処理を挟まないと例外で止まるので注意!

Windows Phone は SDK をそのまま利用すればいいので追加実装なし

そして ViewModel

/// <summary>
/// トップ画面の ViewModel
/// </summary>
public class TopPageViewModel : BindableBase
{
    ~ 中略 ~

    /// <summary>
    /// 接続処理
    /// </summary>
    /// <returns>Task</returns>
    private async Task Connect()
    {
        var devices = await this.manager.GetBandsAsync();
            
        if (!devices.Any())
        {
            await App.Current.MainPage.DisplayAlert("Warning", "No Microsoft Band found.", "OK");
            return;
        }

        var device = devices.First();
        this.ConnectMessage = "Connecting to Band...";
        var client = await this.manager.ConnectAsync(device);

        if (client == null)
        {
            await App.Navigation.CurrentPage.DisplayAlert(
                "Error",
                string.Format("Failed to connect to Microsoft Band '{0}'.", device.Name),
                "OK");
            return;
        }

        // 別の場所から利用できるように DI コンテナに登録
        App.Container.RegisterInstance<IBandClient>(client, new ContainerControlledLifetimeManager());
        App.Container.RegisterInstance<IBandInfo>(device, new ContainerControlledLifetimeManager());

        this.ConnectMessage = string.Empty;
        this.BandName = device.Name;
        this.HardwareVersion = await this.service.GetHardwareVersionAsync();
        this.FirmwareVersion = await this.service.GetFirmwareVersionAsync();

        this.IsConnected = true;
        await App.Current.MainPage.DisplayAlert(
            "Connected",
            string.Format("Microsoft Band '{0}' connected.", device.Name),
            "OK");
    }
}

接続後に情報取得を追加しただけ

これに合わせて XAML も変更

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cv="clr-namespace:XamarinBandSample.Converters;assembly=XamarinBandSample"
             xmlns:prismmvvm="clr-namespace:Prism.Mvvm;assembly=XamarinBandSample"
             prismmvvm:ViewModelLocator.AutoWireViewModel="true"
             x:Class="XamarinBandSample.Views.TopPage">
  <ContentPage.Resources>
    <ResourceDictionary>
      <cv:NegativeConverter x:Key="NegativeConverter"/>
    </ResourceDictionary>
  </ContentPage.Resources>
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0"/>
  </ContentPage.Padding>

  <StackLayout Orientation="Vertical"
               Padding="10"
               Spacing="10">
    
    <Label Text="Band Test"
           FontSize="Large"
           HorizontalOptions="Center"
           VerticalOptions="Center"/>

    <StackLayout Orientation="Vertical"
                 Spacing="5">
      <Button Text="Connect Band"
              FontSize="Medium"
              HorizontalOptions="Start"
              VerticalOptions="Center"
              IsEnabled="{Binding IsConnected, Converter={StaticResource NegativeConverter}}"
              Command="{Binding ConnectCommand}"/>
      <Grid Padding="20,0">
        <Label Text="{Binding ConnectMessage}"
               HeightRequest="20"
               Opacity="0.6"
               FontSize="Small"/>
      </Grid>
    </StackLayout>

    <StackLayout Orientation="Vertical"
                 Spacing="5">
      <Label Text="Device Name:"
             FontSize="Medium"/>
      <Grid Padding="20,0">
        <Label Text="{Binding BandName}"
               HeightRequest="20"
               FontSize="Small"/>
      </Grid>
    </StackLayout>

    <StackLayout Orientation="Vertical"
                 Spacing="5">
      <Label Text="Hardware Version:"
             FontSize="Medium"/>
      <Grid Padding="20,0">
        <Label Text="{Binding HardwareVersion}"
               HeightRequest="20"
               FontSize="Small"/>
      </Grid>
    </StackLayout>

    <StackLayout Orientation="Vertical"
                 Spacing="5">
      <Label Text="Firmware Version:"
             FontSize="Medium"/>
      <Grid Padding="20,0">
        <Label Text="{Binding FirmwareVersion}"
               HeightRequest="20"
               FontSize="Small"/>
      </Grid>
    </StackLayout>

  </StackLayout>
  
</ContentPage>

お試し実行

f:id:matatabi_ux:20150418233326p:plain f:id:matatabi_ux:20150418233334p:plain

ちゃんと取れているみたいですね