http://geoffwebbercross.blogspot.co.uk/2012/12/pushing-file-from-wp8-using-bluetooth.html
So here's the View Model example:
using
BluetoothApp.Commanding;
using BluetoothApp.Helpers;
using
BluetoothApp.Services.Interfaces;
using GalaSoft.MvvmLight;
using System;
using
System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using
System.Threading.Tasks;
using System.Windows.Media;
using WebberCross.Obelisk;
using
Windows.Networking.Proximity;
using
Windows.Networking.Sockets;
using
Windows.Storage.Streams;
namespace
BluetoothApp.ViewModel
{
public class BluetoothShareVM : ViewModelBase
{
const string FILE_NAME = "demo.jpg";
private readonly INavigationService _navService = null;
private readonly ITaskService _taskService = null;
private readonly IDialogService _diaService = null;
private IReadOnlyList<PeerInformation> _pairedDevices
= null;
private StreamSocket _stream = null;
private DataWriter _dataWriter = null;
private DataReader _dataReader = null;
private byte[] _shareData = null;
private Brush _thumbnail = null;
private DelegateCommand _shareCommand = null;
private bool _isLoading = false;
private bool _isShareExecutable = true;
private string _message = Resources.StringTable.BTSearching;
private bool _isShareVisible = false;
private PeerInformation _selectedDevice = null;
private int _progress = 0;
private string _shareStatus =
Resources.StringTable.BTSending;
public string BTShareTitle { get { return
Resources.StringTable.BTShareTitle; } }
public string BTShareHeading { get { return
Resources.StringTable.BTShareHeading; } }
public string ShareText { get { return Resources.StringTable.ShareText; } }
public string LogoutText { get { return Resources.StringTable.LogoutText; } }
public string CheckPeersWarning { get { return
Resources.StringTable.CheckPeersWarning; } }
public string DevicesText { get { return Resources.StringTable.DevicesText; } }
public string StatusText { get { return Resources.StringTable.StatusText; } }
private List<byte[]> _packets = null;
public byte[] ShareData
{
get { return this._shareData; }
set
{
if (this._shareData != value)
{
this._shareData = value;
base.RaisePropertyChanged("ShareData");
}
}
}
public string Message
{
get { return this._message; }
set
{
if (this._message != value)
{
this._message = value;
base.RaisePropertyChanged("Message");
}
}
}
public string ShareStatus
{
get { return this._shareStatus; }
set
{
if (this._shareStatus != value)
{
this._shareStatus = value;
base.RaisePropertyChanged("ShareStatus");
}
}
}
public int Progress
{
get { return this._progress; }
set
{
if (this._progress != value)
{
this._progress = value;
base.RaisePropertyChanged("Progress");
}
}
}
public Brush Thumbnail
{
get
{
if (this._thumbnail == null && this._shareData != null)
{
this._thumbnail =
Imaging.GetImageBrush(this._shareData, 0);
}
return _thumbnail;
}
}
public bool IsLoading
{
get { return this._isLoading; }
set
{
if (this._isLoading != value)
{
this._isLoading = value;
base.RaisePropertyChanged("IsLoading");
}
}
}
public bool IsShareVisible
{
get { return this._isShareVisible; }
set
{
if (this._isShareVisible != value)
{
this._isShareVisible = value;
base.RaisePropertyChanged("IsShareVisible");
}
}
}
public DelegateCommand ShareCommand
{
get { return this._shareCommand; }
}
public bool IsShareExecutable
{
get { return this._isShareExecutable; }
set
{
if (this._isShareExecutable != value)
{
this._isShareExecutable = value;
base.RaisePropertyChanged("IsShareExecutable");
this._shareCommand.RaiseCanExecuteChanged();
}
}
}
public IReadOnlyList<PeerInformation> PairedDevices
{
get { return this._pairedDevices; }
set
{
if (this._pairedDevices != value)
{
this._pairedDevices = value;
base.RaisePropertyChanged("PairedDevices");
}
}
}
public PeerInformation SelectedDevice
{
get { return this._selectedDevice; }
set
{
this.IsShareExecutable = value != null;
if (this._selectedDevice != value)
{
this._selectedDevice = value;
base.RaisePropertyChanged("SelectedDevice");
}
}
}
/// <summary>
/// Initializes a new instance of the
FacebookShareViewModel class.
/// </summary>
public BluetoothShareVM(INavigationService
navService, ITaskService taskService, IDialogService diaService)
{
if (IsInDesignMode)
{
// Code runs in Blend --> create
design time data.
}
else
{
// Code runs "for real":
Connect to service, etc...
this._navService = navService;
this._taskService = taskService;
this._diaService = diaService;
this.InitialiseCommands();
this.Search();
}
}
private void InitialiseCommands()
{
// Background
this._shareCommand = new
DelegateCommand((param) =>
{
this.Share();
},
(p) =>
{
return this.IsShareExecutable;
});
}
private async void Search()
{
this.IsLoading = true;
this.IsShareExecutable = false;
this.Message = Resources.StringTable.BTSearching;
// Note: You can only browse and connect to
paired devices!
// Configure PeerFinder to search for all
paired devices.
PeerFinder.AlternateIdentities["Bluetooth:Paired"] = "";
try
{
this.PairedDevices = await PeerFinder.FindAllPeersAsync();
}
catch (Exception)
{
}
this.IsLoading = false;
}
private async Task Share()
{
this.IsShareVisible = true;
this.IsShareExecutable = false;
this.ShareStatus =
Resources.StringTable.BTSending;
this.CreatePackets();
// Select a paired device. In this example,
just pick the first one.
// Attempt a connection
_stream = new StreamSocket();
try
{
// Make sure ID_CAP_NETWORKING is
enabled in your WMAppManifest.xml, or the next
// line will throw an Access Denied
exception.
string oopUUID = "{00001105-0000-1000-8000-00805f9b34fb}";
await
_stream.ConnectAsync(_selectedDevice.HostName, oopUUID);
_dataWriter = new
DataWriter(_stream.OutputStream);
_dataReader = new
DataReader(_stream.InputStream);
// Send data
int maxServerPacket = await this.ObexConnect();
if (maxServerPacket > 0)
{
if (await ObexPushRequest())
{
// Success
this.ShareStatus =
Resources.StringTable.BTSuccess;
}
else
{
// Failed
this.ShareStatus =
Resources.StringTable.BTFailed;
}
this.Progress = 100;
}
this.ObexDisconnect();
}
catch (Exception ex)
{
this.ShareStatus =
Resources.StringTable.BTFailed;
}
}
private async Task<int> ObexConnect()
{
//send client request
byte[] ConnectPacket = new byte[7];
ConnectPacket[0] = 0x80; // Connect
ConnectPacket[1] = (7 & 0xFF00)
>> 8; // Packetlength Hi
Byte
ConnectPacket[2] = (7 &
0xFF); // Packetlength Lo
Byte
ConnectPacket[3] = 0x10; // Obex v1
ConnectPacket[4] = 0x00; // No flags
ConnectPacket[5] = (2048 &
0xFF00) >> 8; // 2048 byte client
max packet size Hi Byte
ConnectPacket[6] = (2048 &
0xFF); // 2048 byte max
packet size Lo Byte
_dataWriter.WriteBytes(ConnectPacket);
await _dataWriter.StoreAsync();
// Get response code
await _dataReader.LoadAsync(1);
byte[] buffer = new byte[1];
_dataReader.ReadBytes(buffer);
if (buffer[0] == 0xA0) // Sucess
{
// Get length
await _dataReader.LoadAsync(2);
buffer = new byte[2];
_dataReader.ReadBytes(buffer);
int length = buffer[0] << 8;
length += buffer[1];
// Get rest of packet
await _dataReader.LoadAsync((uint)length - 3);
buffer = new byte[length - 3];
_dataReader.ReadBytes(buffer);
int obexVersion = buffer[0];
int flags = buffer[1];
int maxServerPacket = buffer[2] << 8 +
buffer[3];
return maxServerPacket;
}
else
{
return -1;
}
}
private async void ObexDisconnect()
{
byte[] bytes = new byte[3];
bytes[0] = 0x81;
bytes[1] = 0;
bytes[2] = 3;
_dataWriter.WriteBytes(bytes);
await _dataWriter.StoreAsync();
await _dataReader.LoadAsync(3);
byte[] response = new byte[3];
_dataReader.ReadBytes(response);
_stream.Dispose();
_stream = null;
_dataReader.Dispose();
_dataWriter.Dispose();
}
private async Task<bool> ObexPushRequest()
{
int step = 100 / this._packets.Count;
foreach (var packet in this._packets)
{
this.Progress += step;
_dataWriter.WriteBytes(packet);
await _dataWriter.StoreAsync();
// Get response code
await _dataReader.LoadAsync(3);
byte[] buffer = new byte[3];
_dataReader.ReadBytes(buffer);
// If not success and not continue it's
an error
if (buffer[0] != 0xA0 && buffer[0] !=
0x90)
return false;
else if (buffer[0] == 0xA0) // Success
return true;
}
return false;
}
private void CreatePackets()
{
int bodyLength = 1024;
this._packets = new List<byte[]>();
// Chop data into packets
int blocks = (int)Math.Ceiling((decimal)this._shareData.Length / bodyLength);
System.Text.UnicodeEncoding encoding = new System.Text.UnicodeEncoding(true, false);
byte[] encodedName = encoding.GetBytes(FILE_NAME
+ new char());
for (int i = 0; i < blocks; i++)
{
int headerLength = i == 0 ? 14 +
encodedName.Length : 6;
// Chop data into body
byte[] body = null;
if (i < blocks - 1)
body = new byte[bodyLength];
else
body = new byte[this._shareData.Length -
(i * bodyLength)];
System.Buffer.BlockCopy(this._shareData, i *
bodyLength, body, 0, body.Length);
// Create packet
byte[] packet = new byte[headerLength + body.Length];
this._packets.Add(packet);
// Build packet
int offset = 0;
packet[offset++] = i != blocks
- 1 ? (byte)0x02 : (byte)0x82; // 0x02 for first
blocks, 0x82 for last
packet[offset++] = (byte)((packet.Length &
0xFF00) >> 8);
packet[offset++] = (byte)(packet.Length &
0xFF);
// Payload details on first packet
if (i == 0)
{
packet[offset++] = 0x01; // Name header
packet[offset++] = (byte)(((encodedName.Length
+ 3) & 0xFF00) >> 8);
packet[offset++] = (byte)((encodedName.Length
+ 3) & 0xFF);
System.Buffer.BlockCopy(encodedName,
0, packet, offset, encodedName.Length);
offset +=
encodedName.Length;
packet[offset++] = 0xC3; // Length header
packet[offset++] = (byte)((this._shareData.Length
& 0xFF000000) >> 24);
packet[offset++] = (byte)((this._shareData.Length
& 0xFF0000) >> 16);
packet[offset++] = (byte)((this._shareData.Length
& 0xFF00) >> 8);
packet[offset++] = (byte)(this._shareData.Length
& 0xFF);
}
packet[offset++] = 0x48; // Object body chunk
header
packet[offset++] = (byte)(((body.Length + 3)
& 0xFF00) >> 8);
packet[offset++] = (byte)((body.Length + 3)
& 0xFF);
System.Buffer.BlockCopy(body, 0,
packet, offset, body.Length);
}
}
}
}
And here's the View XAML:
<phone:PhoneApplicationPage x:Class="BluetoothApp.Pages.BluetoothShareView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:preview="clr-namespace:Phone7.Fx.Preview;assembly=Phone7.Fx.Preview"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:BluetoothApp.Commanding"
mc:Ignorable="d"
d:DesignWidth="480"
d:DesignHeight="728"
FontFamily="{StaticResource
PhoneFontFamilyNormal}"
FontSize="{StaticResource
PhoneFontSizeNormal}"
Foreground="{StaticResource
PhoneForegroundBrush}"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="False"
DataContext="{Binding Bluetooth,
Source={StaticResource Locator}}">
<toolkit:TransitionService.NavigationInTransition>
<toolkit:NavigationInTransition>
<toolkit:NavigationInTransition.Backward>
<toolkit:TurnstileTransition Mode="BackwardIn"/>
</toolkit:NavigationInTransition.Backward>
<toolkit:NavigationInTransition.Forward>
<toolkit:TurnstileTransition Mode="ForwardIn"/>
</toolkit:NavigationInTransition.Forward>
</toolkit:NavigationInTransition>
</toolkit:TransitionService.NavigationInTransition>
<toolkit:TransitionService.NavigationOutTransition>
<toolkit:NavigationOutTransition>
<toolkit:NavigationOutTransition.Backward>
<toolkit:TurnstileTransition Mode="BackwardOut"/>
</toolkit:NavigationOutTransition.Backward>
<toolkit:NavigationOutTransition.Forward>
<toolkit:TurnstileTransition Mode="ForwardOut"/>
</toolkit:NavigationOutTransition.Forward>
</toolkit:NavigationOutTransition>
</toolkit:TransitionService.NavigationOutTransition>
<Grid x:Name="LayoutRoot" Background="{StaticResource BackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<toolkit:PerformanceProgressBar Margin="0,-110,0,0" Padding="0" IsIndeterminate="True" IsEnabled="{Binding
Path=IsLoading}" Visibility="{Binding IsLoading, Converter={StaticResource visConverter}}" />
<ProgressBar Margin="24,-110,24,0" Padding="0" Minimum="0" Maximum="100" Value="{Binding Progress}" Visibility="{Binding
IsShareVisible, Converter={StaticResource visConverter}}" />
<!--TitlePanel contains the name of the
application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,0">
<TextBlock Text="{Binding
Path=BTShareTitle, Mode=OneTime, FallbackValue=TITLE}" Style="{StaticResource
PhoneTextNormalStyle}" />
<TextBlock Text="{Binding
Path=BTShareHeading, Mode=OneTime, FallbackValue=heading}" Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}" />
</StackPanel>
<!--ContentPanel - place additional content
here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="24,0,24,0">
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle Fill="{Binding
Path=Thumbnail, FallbackValue=Red}" Height="200" Width="120" Stretch="Fill" HorizontalAlignment="Center" />
<Grid Grid.Row="1" Visibility="{Binding IsShareVisible, Converter={StaticResource
visConverter}, ConverterParameter='invert'}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Margin="0,20,0,0" Text="{Binding
CheckPeersWarning}" Style="{StaticResource PhoneTextNormalStyle}"
TextWrapping="Wrap"/>
<TextBlock Margin="0,20,0,0" Grid.Row="1" Text="{Binding DevicesText}" Style="{StaticResource
PhoneTextTitle2Style}" />
<ListBox Grid.Row="2" ItemsSource="{Binding PairedDevices}" SelectedItem="{Binding
SelectedDevice, Mode=TwoWay}"
DisplayMemberPath="DisplayName" Margin="0,10,0,0" FontSize="{StaticResource PhoneFontSizeMediumLarge}">
</ListBox>
</Grid>
<Grid Grid.Row="1" Visibility="{Binding IsShareVisible, Converter={StaticResource
visConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Margin="0,20,0,0" Text="{Binding StatusText}" Style="{StaticResource
PhoneTextTitle2Style}" />
<TextBlock Grid.Row="2" Margin="0,20,0,0" Text="{Binding ShareStatus}" Style="{StaticResource
PhoneTextNormalStyle}"
TextWrapping="Wrap"/>
</Grid>
</Grid>
<preview:BindableApplicationBar BackgroundColor="#FFD82735">
<preview:BindableApplicationBarIconButton IsEnabled="{Binding
Path=IsShareExecutable}" Command="{Binding Path=ShareCommand}" IconUri="/Images/send.png" Text="{Binding Path=ShareText, Mode=OneTime}" />
</preview:BindableApplicationBar>
</Grid>
</phone:PhoneApplicationPage>
No comments:
Post a Comment