diff --git a/Samples/BackgroundTransfer/cpp/Tasks/CompletionGroupTask.cpp b/Samples/BackgroundTransfer/cpp/Tasks/CompletionGroupTask.cpp
index c58f14a48e..5af2fd8db4 100644
--- a/Samples/BackgroundTransfer/cpp/Tasks/CompletionGroupTask.cpp
+++ b/Samples/BackgroundTransfer/cpp/Tasks/CompletionGroupTask.cpp
@@ -104,6 +104,8 @@ BackgroundDownloader^ CompletionGroupTask::CreateBackgroundDownloader()
builder->SetTrigger(completionGroup->Trigger);
+ // The system automatically unregisters the BackgroundTransferCompletionGroup task when it triggers.
+ // You do not need to unregister it explicitly.
BackgroundTaskRegistration^ taskRegistration = builder->Register();
BackgroundDownloader^ downloader = ref new BackgroundDownloader(completionGroup);
diff --git a/Samples/BackgroundTransfer/cs/Tasks/CompletionGroupTask.cs b/Samples/BackgroundTransfer/cs/Tasks/CompletionGroupTask.cs
index 48375f1ded..8f0e8e9334 100644
--- a/Samples/BackgroundTransfer/cs/Tasks/CompletionGroupTask.cs
+++ b/Samples/BackgroundTransfer/cs/Tasks/CompletionGroupTask.cs
@@ -133,6 +133,8 @@ public static BackgroundDownloader CreateBackgroundDownloader()
builder.TaskEntryPoint = "Tasks.CompletionGroupTask";
builder.SetTrigger(completionGroup.Trigger);
+ // The system automatically unregisters the BackgroundTransferCompletionGroup task when it triggers.
+ // You do not need to unregister it explicitly.
BackgroundTaskRegistration taskRegistration = builder.Register();
BackgroundDownloader downloader = new BackgroundDownloader(completionGroup);
diff --git a/Samples/BackgroundTransfer/js/js/completionGroupBackgroundTask.js b/Samples/BackgroundTransfer/js/js/completionGroupBackgroundTask.js
index 1085830b79..fc0b1bb35a 100644
--- a/Samples/BackgroundTransfer/js/js/completionGroupBackgroundTask.js
+++ b/Samples/BackgroundTransfer/js/js/completionGroupBackgroundTask.js
@@ -73,6 +73,9 @@
var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.taskEntryPoint = taskEntryPoint;
builder.setTrigger(completionGroup.trigger);
+
+ // The system automatically unregisters the BackgroundTransferCompletionGroup task when it triggers.
+ // You do not need to unregister it explicitly.
var taskRegistration = builder.register();
var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader(completionGroup);
diff --git a/Samples/BackgroundTransfer/vb/Tasks/CompletionGroupTask.vb b/Samples/BackgroundTransfer/vb/Tasks/CompletionGroupTask.vb
index fa9150b12a..5c6687e804 100644
--- a/Samples/BackgroundTransfer/vb/Tasks/CompletionGroupTask.vb
+++ b/Samples/BackgroundTransfer/vb/Tasks/CompletionGroupTask.vb
@@ -90,7 +90,11 @@ Namespace Global.Tasks
Dim builder As BackgroundTaskBuilder = New BackgroundTaskBuilder()
builder.TaskEntryPoint = "Tasks.CompletionGroupTask"
builder.SetTrigger(completionGroup.Trigger)
+
+ ' The system automatically unregisters the BackgroundTransferCompletionGroup task when it triggers.
+ ' You do not need to unregister it explicitly.
Dim taskRegistration As BackgroundTaskRegistration = builder.Register()
+
Dim downloader As BackgroundDownloader = New BackgroundDownloader(completionGroup)
Return downloader
End Function
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLE.sln b/Samples/BluetoothLE/cppwinrt/BluetoothLE.sln
new file mode 100644
index 0000000000..437df5dec5
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLE.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.168
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BluetoothLE", "BluetoothLE.vcxproj", "{6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|ARM.ActiveCfg = Debug|ARM
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|ARM.Build.0 = Debug|ARM
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|ARM.Deploy.0 = Debug|ARM
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|x64.ActiveCfg = Debug|x64
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|x64.Build.0 = Debug|x64
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|x64.Deploy.0 = Debug|x64
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|x86.ActiveCfg = Debug|Win32
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|x86.Build.0 = Debug|Win32
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Debug|x86.Deploy.0 = Debug|Win32
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|ARM.ActiveCfg = Release|ARM
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|ARM.Build.0 = Release|ARM
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|ARM.Deploy.0 = Release|ARM
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|x64.ActiveCfg = Release|x64
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|x64.Build.0 = Release|x64
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|x64.Deploy.0 = Release|x64
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|x86.ActiveCfg = Release|Win32
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|x86.Build.0 = Release|Win32
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B7CCE8FC-0342-4D8C-AA55-C89A6673C44A}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLE.vcxproj b/Samples/BluetoothLE/cppwinrt/BluetoothLE.vcxproj
new file mode 100644
index 0000000000..8899abba75
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLE.vcxproj
@@ -0,0 +1,211 @@
+
+
+
+
+ true
+ {6BA13EC4-5ACC-4B1A-99B4-6FC4D67C7849}
+ BluetoothLE
+ SDKTemplate
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.17763.0
+ $(WindowsTargetPlatformVersion)
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ v141
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+ $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\..\SharedContent\cppwinrt
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ ..\..\..\SharedContent\xaml\App.xaml
+
+
+ ..\..\..\SharedContent\xaml\MainPage.xaml
+
+
+
+
+
+
+
+ ..\shared\Scenario1_Discovery.xaml
+
+
+ ..\shared\Scenario2_Client.xaml
+
+
+ ..\shared\Scenario3_ServerForeground.xaml
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+
+ Styles\Styles.xaml
+
+
+
+
+ ..\..\..\SharedContent\xaml\App.xaml
+
+
+ ..\..\..\SharedContent\xaml\MainPage.xaml
+
+
+ BluetoothLEAttributeDisplay.h
+
+
+ BluetoothLEDeviceDisplay.h
+
+
+ Create
+ pch.h
+
+
+ SampleConfiguration.h
+
+
+ ..\shared\Scenario1_Discovery.xaml
+
+
+ ..\shared\Scenario2_Client.xaml
+
+
+ ..\shared\Scenario3_ServerForeground.xaml
+
+
+
+
+
+ ..\..\..\SharedContent\xaml\App.xaml
+
+
+ ..\..\..\SharedContent\xaml\MainPage.xaml
+
+
+
+ ..\shared\Scenario1_Discovery.xaml
+
+
+ ..\shared\Scenario2_Client.xaml
+
+
+ ..\shared\Scenario3_ServerForeground.xaml
+
+
+
+
+ Designer
+
+
+
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLE.vcxproj.filters b/Samples/BluetoothLE/cppwinrt/BluetoothLE.vcxproj.filters
new file mode 100644
index 0000000000..8333300f8d
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLE.vcxproj.filters
@@ -0,0 +1,80 @@
+
+
+
+
+ 4416d50a-7676-4d0a-9b2c-91ff70c6047f
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLEAttributeDisplay.cpp b/Samples/BluetoothLE/cppwinrt/BluetoothLEAttributeDisplay.cpp
new file mode 100644
index 0000000000..82e6714737
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLEAttributeDisplay.cpp
@@ -0,0 +1,223 @@
+#include "pch.h"
+#include "BluetoothLEAttributeDisplay.h"
+
+using namespace winrt;
+using namespace Windows::Devices::Bluetooth::GenericAttributeProfile;
+
+namespace
+{
+ ///
+ /// Determines whether the UUID was assigned by the Bluetooth SIG.
+ /// If so, extracts the assigned number.
+ ///
+
+ bool TryParseSigDefinedUuid(guid const& uuid, uint16_t& shortId)
+ {
+ // UUIDs defined by the Bluetooth SIG are of the form
+ // 0000xxxx-0000-1000-8000-00805F9B34FB.
+ constexpr guid BluetoothGuid = { 0x00000000, 0x0000, 0x1000, { 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB } };
+
+ shortId = static_cast(uuid.Data1);
+ guid possibleBluetoothGuid = uuid;
+ possibleBluetoothGuid.Data1 &= 0xFFFF0000;
+ return possibleBluetoothGuid == BluetoothGuid;
+ }
+
+ hstring GetGattServiceFriendlyName(guid const& uuid)
+ {
+ uint16_t shortId;
+
+ if (TryParseSigDefinedUuid(uuid, shortId))
+ {
+ // Reference: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
+ const static std::map knownServiceIds =
+ {
+ { 0x0000, L"None" },
+ { 0x1811, L"AlertNotification" },
+ { 0x180F, L"Battery" },
+ { 0x1810, L"BloodPressure" },
+ { 0x1805, L"CurrentTimeService" },
+ { 0x1816, L"CyclingSpeedandCadence" },
+ { 0x180A, L"DeviceInformation" },
+ { 0x1800, L"GenericAccess" },
+ { 0x1801, L"GenericAttribute" },
+ { 0x1808, L"Glucose" },
+ { 0x1809, L"HealthThermometer" },
+ { 0x180D, L"HeartRate" },
+ { 0x1812, L"HumanInterfaceDevice" },
+ { 0x1802, L"ImmediateAlert" },
+ { 0x1803, L"LinkLoss" },
+ { 0x1807, L"NextDSTChange" },
+ { 0x180E, L"PhoneAlertStatus" },
+ { 0x1806, L"ReferenceTimeUpdateService" },
+ { 0x1814, L"RunningSpeedandCadence" },
+ { 0x1813, L"ScanParameters" },
+ { 0x1804, L"TxPower" },
+ { 0xFFE0, L"SimpleKeyService" },
+ };
+ auto it = knownServiceIds.find(shortId);
+ if (it != knownServiceIds.end())
+ {
+ return it->second;
+ }
+ }
+ return L"Custom service: " + to_hstring(uuid);
+ }
+
+ hstring GetGattCharacteristicFriendlyName(guid const& uuid, hstring const& userDescription)
+ {
+ uint16_t shortId;
+
+ if (TryParseSigDefinedUuid(uuid, shortId))
+ {
+ // Reference: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx
+ const static std::map knownCharacteristicIds =
+ {
+ { 0x0000, L"None" },
+ { 0x2A43, L"AlertCategoryID" },
+ { 0x2A42, L"AlertCategoryIDBitMask" },
+ { 0x2A06, L"AlertLevel" },
+ { 0x2A44, L"AlertNotificationControlPoint" },
+ { 0x2A3F, L"AlertStatus" },
+ { 0x2A01, L"Appearance" },
+ { 0x2A19, L"BatteryLevel" },
+ { 0x2A49, L"BloodPressureFeature" },
+ { 0x2A35, L"BloodPressureMeasurement" },
+ { 0x2A38, L"BodySensorLocation" },
+ { 0x2A22, L"BootKeyboardInputReport" },
+ { 0x2A32, L"BootKeyboardOutputReport" },
+ { 0x2A33, L"BootMouseInputReport" },
+ { 0x2A5C, L"CSCFeature" },
+ { 0x2A5B, L"CSCMeasurement" },
+ { 0x2A2B, L"CurrentTime" },
+ { 0x2A08, L"DateTime" },
+ { 0x2A0A, L"DayDateTime" },
+ { 0x2A09, L"DayofWeek" },
+ { 0x2A00, L"DeviceName" },
+ { 0x2A0D, L"DSTOffset" },
+ { 0x2A0C, L"ExactTime256" },
+ { 0x2A26, L"FirmwareRevisionString" },
+ { 0x2A51, L"GlucoseFeature" },
+ { 0x2A18, L"GlucoseMeasurement" },
+ { 0x2A34, L"GlucoseMeasurementContext" },
+ { 0x2A27, L"HardwareRevisionString" },
+ { 0x2A39, L"HeartRateControlPoint" },
+ { 0x2A37, L"HeartRateMeasurement" },
+ { 0x2A4C, L"HIDControlPoint" },
+ { 0x2A4A, L"HIDInformation" },
+ { 0x2A2A, L"IEEE11073_20601RegulatoryCertificationDataList" },
+ { 0x2A36, L"IntermediateCuffPressure" },
+ { 0x2A1E, L"IntermediateTemperature" },
+ { 0x2A0F, L"LocalTimeInformation" },
+ { 0x2A29, L"ManufacturerNameString" },
+ { 0x2A21, L"MeasurementInterval" },
+ { 0x2A24, L"ModelNumberString" },
+ { 0x2A46, L"NewAlert" },
+ { 0x2A04, L"PeripheralPreferredConnectionParameters" },
+ { 0x2A02, L"PeripheralPrivacyFlag" },
+ { 0x2A50, L"PnPID" },
+ { 0x2A4E, L"ProtocolMode" },
+ { 0x2A03, L"ReconnectionAddress" },
+ { 0x2A52, L"RecordAccessControlPoint" },
+ { 0x2A14, L"ReferenceTimeInformation" },
+ { 0x2A4D, L"Report" },
+ { 0x2A4B, L"ReportMap" },
+ { 0x2A40, L"RingerControlPoint" },
+ { 0x2A41, L"RingerSetting" },
+ { 0x2A54, L"RSCFeature" },
+ { 0x2A53, L"RSCMeasurement" },
+ { 0x2A55, L"SCControlPoint" },
+ { 0x2A4F, L"ScanIntervalWindow" },
+ { 0x2A31, L"ScanRefresh" },
+ { 0x2A5D, L"SensorLocation" },
+ { 0x2A25, L"SerialNumberString" },
+ { 0x2A05, L"ServiceChanged" },
+ { 0x2A28, L"SoftwareRevisionString" },
+ { 0x2A47, L"SupportedNewAlertCategory" },
+ { 0x2A48, L"SupportedUnreadAlertCategory" },
+ { 0x2A23, L"SystemID" },
+ { 0x2A1C, L"TemperatureMeasurement" },
+ { 0x2A1D, L"TemperatureType" },
+ { 0x2A12, L"TimeAccuracy" },
+ { 0x2A13, L"TimeSource" },
+ { 0x2A16, L"TimeUpdateControlPoint" },
+ { 0x2A17, L"TimeUpdateState" },
+ { 0x2A11, L"TimewithDST" },
+ { 0x2A0E, L"TimeZone" },
+ { 0x2A07, L"TxPowerLevel" },
+ { 0x2A45, L"UnreadAlertStatus" },
+ { 0x2A5A, L"AggregateInput" },
+ { 0x2A58, L"AnalogInput" },
+ { 0x2A59, L"AnalogOutput" },
+ { 0x2A66, L"CyclingPowerControlPoint" },
+ { 0x2A65, L"CyclingPowerFeature" },
+ { 0x2A63, L"CyclingPowerMeasurement" },
+ { 0x2A64, L"CyclingPowerVector" },
+ { 0x2A56, L"DigitalInput" },
+ { 0x2A57, L"DigitalOutput" },
+ { 0x2A0B, L"ExactTime100" },
+ { 0x2A6B, L"LNControlPoint" },
+ { 0x2A6A, L"LNFeature" },
+ { 0x2A67, L"LocationandSpeed" },
+ { 0x2A68, L"Navigation" },
+ { 0x2A3E, L"NetworkAvailability" },
+ { 0x2A69, L"PositionQuality" },
+ { 0x2A3C, L"ScientificTemperatureinCelsius" },
+ { 0x2A10, L"SecondaryTimeZone" },
+ { 0x2A3D, L"String" },
+ { 0x2A1F, L"TemperatureinCelsius" },
+ { 0x2A20, L"TemperatureinFahrenheit" },
+ { 0x2A15, L"TimeBroadcast" },
+ { 0x2A1B, L"BatteryLevelState" },
+ { 0x2A1A, L"BatteryPowerState" },
+ { 0x2A5F, L"PulseOximetryContinuousMeasurement" },
+ { 0x2A62, L"PulseOximetryControlPoint" },
+ { 0x2A61, L"PulseOximetryFeatures" },
+ { 0x2A60, L"PulseOximetryPulsatileEvent" },
+ { 0xFFE1, L"SimpleKeyState" },
+ };
+
+ auto it = knownCharacteristicIds.find(shortId);
+ if (it != knownCharacteristicIds.end())
+ {
+ return it->second;
+ }
+ }
+ if (!userDescription.empty())
+ {
+ return userDescription;
+ }
+
+ return L"Custom Characteristic: " + to_hstring(uuid);
+ }
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+ hstring BluetoothLEAttributeDisplay::Name()
+ {
+ switch (m_attributeType)
+ {
+ case AttributeType::Service:
+ return GetGattServiceFriendlyName(m_service.Uuid());
+
+ case AttributeType::Characteristic:
+ return GetGattCharacteristicFriendlyName(m_characteristic.Uuid(), m_characteristic.UserDescription());
+ }
+ return L"Invalid";
+ }
+
+ hstring BluetoothLEAttributeDisplay::AttributeDisplayType()
+ {
+ switch (m_attributeType)
+ {
+ case AttributeType::Service:
+ return L"Service";
+ case AttributeType::Characteristic:
+ return L"Characteristic";
+ case AttributeType::Descriptor:
+ return L"Descriptor";
+ }
+ return L"Invalid";
+ }
+}
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLEAttributeDisplay.h b/Samples/BluetoothLE/cppwinrt/BluetoothLEAttributeDisplay.h
new file mode 100644
index 0000000000..5b18b8a6b5
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLEAttributeDisplay.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "BluetoothLEAttributeDisplay.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct BluetoothLEAttributeDisplay : BluetoothLEAttributeDisplayT
+ {
+ BluetoothLEAttributeDisplay(Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceService const& service)
+ : m_service(service), m_attributeType(SDKTemplate::AttributeType::Service)
+ {
+ }
+
+ BluetoothLEAttributeDisplay(Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic const& characteristic)
+ : m_characteristic(characteristic), m_attributeType(SDKTemplate::AttributeType::Characteristic)
+ {
+ }
+
+ Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic characteristic()
+ {
+ return m_characteristic;
+ }
+
+ void characteristic(Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic const& value)
+ {
+ m_characteristic = value;
+ }
+
+ Windows::Devices::Bluetooth::GenericAttributeProfile::GattDescriptor descriptor()
+ {
+ return m_descriptor;
+ }
+
+ void descriptor(Windows::Devices::Bluetooth::GenericAttributeProfile::GattDescriptor const& value)
+ {
+ m_descriptor = value;
+ }
+
+ Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceService service()
+ {
+ return m_service;
+ }
+
+ void service(Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceService const& value)
+ {
+ m_service = value;
+ }
+
+ hstring Name();
+ hstring AttributeDisplayType();
+
+ static SDKTemplate::BluetoothLEAttributeDisplay CreateFromService(Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceService const& service)
+ {
+ return BluetoothLEAttributeDisplay(service);
+ }
+
+ static SDKTemplate::BluetoothLEAttributeDisplay CreateFromCharacteristic(Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic const& characteristic)
+ {
+ return BluetoothLEAttributeDisplay(characteristic);
+ }
+
+ private:
+ Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic m_characteristic{ nullptr };
+ Windows::Devices::Bluetooth::GenericAttributeProfile::GattDescriptor m_descriptor{ nullptr };
+ Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceService m_service{ nullptr };
+ SDKTemplate::AttributeType m_attributeType;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct BluetoothLEAttributeDisplay : BluetoothLEAttributeDisplayT
+ {
+ };
+}
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLEDeviceDisplay.cpp b/Samples/BluetoothLE/cppwinrt/BluetoothLEDeviceDisplay.cpp
new file mode 100644
index 0000000000..e85140c457
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLEDeviceDisplay.cpp
@@ -0,0 +1,63 @@
+#include "pch.h"
+#include "BluetoothLEDeviceDisplay.h"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::UI::Xaml::Data;
+using namespace Windows::UI::Xaml::Media::Imaging;
+
+namespace winrt::SDKTemplate::implementation
+{
+ BluetoothLEDeviceDisplay::BluetoothLEDeviceDisplay(Windows::Devices::Enumeration::DeviceInformation const& deviceInfoIn)
+ : m_deviceInformation(deviceInfoIn)
+ {
+ UpdateGlyphBitmapImage();
+ }
+
+ bool BluetoothLEDeviceDisplay::LookupBooleanProperty(param::hstring const& property)
+ {
+ auto value = m_deviceInformation.Properties().TryLookup(property);
+ return value && unbox_value(value);
+ }
+
+ void BluetoothLEDeviceDisplay::Update(DeviceInformationUpdate const& deviceInfoUpdate)
+ {
+ m_deviceInformation.Update(deviceInfoUpdate);
+
+ OnPropertyChanged(L"Id");
+ OnPropertyChanged(L"Name");
+ OnPropertyChanged(L"DeviceInformation");
+ OnPropertyChanged(L"IsPaired");
+ OnPropertyChanged(L"IsConnected");
+ OnPropertyChanged(L"Properties");
+ OnPropertyChanged(L"IsConnectable");
+
+ UpdateGlyphBitmapImage();
+ }
+
+ event_token BluetoothLEDeviceDisplay::PropertyChanged(PropertyChangedEventHandler const& handler)
+ {
+ return m_propertyChanged.add(handler);
+ }
+
+ void BluetoothLEDeviceDisplay::PropertyChanged(event_token const& token) noexcept
+ {
+ m_propertyChanged.remove(token);
+ }
+
+ void BluetoothLEDeviceDisplay::OnPropertyChanged(param::hstring const& property)
+ {
+ m_propertyChanged(*this, PropertyChangedEventArgs(property));
+ }
+
+ fire_and_forget BluetoothLEDeviceDisplay::UpdateGlyphBitmapImage()
+ {
+ auto lifetime = get_strong();
+ DeviceThumbnail deviceThumbnail = co_await m_deviceInformation.GetGlyphThumbnailAsync();
+ BitmapImage glyphBitmapImage;
+ co_await glyphBitmapImage.SetSourceAsync(deviceThumbnail);
+ m_glyphBitmapImage = glyphBitmapImage;
+ OnPropertyChanged(L"GlyphBitmapImage");
+ }
+}
diff --git a/Samples/BluetoothLE/cppwinrt/BluetoothLEDeviceDisplay.h b/Samples/BluetoothLE/cppwinrt/BluetoothLEDeviceDisplay.h
new file mode 100644
index 0000000000..21ac2c6c43
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/BluetoothLEDeviceDisplay.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "BluetoothLEDeviceDisplay.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct BluetoothLEDeviceDisplay : BluetoothLEDeviceDisplayT
+ {
+ BluetoothLEDeviceDisplay(Windows::Devices::Enumeration::DeviceInformation const& deviceInfoIn);
+
+ Windows::Devices::Enumeration::DeviceInformation DeviceInformation()
+ {
+ return m_deviceInformation;
+ }
+
+ hstring Id()
+ {
+ return m_deviceInformation.Id();
+ }
+
+ hstring Name()
+ {
+ return m_deviceInformation.Name();
+ }
+
+ bool IsPaired()
+ {
+ return m_deviceInformation.Pairing().IsPaired();
+ }
+
+ bool IsConnected()
+ {
+ return LookupBooleanProperty(L"System.Devices.Aep.IsConnected");
+ }
+
+ bool IsConnectable()
+ {
+ return LookupBooleanProperty(L"System.Devices.Aep.Bluetooth.Le.IsConnectable");
+ }
+
+ Windows::Foundation::Collections::IMapView Properties()
+ {
+ return m_deviceInformation.Properties();
+ }
+
+ Windows::UI::Xaml::Media::Imaging::BitmapImage GlyphBitmapImage()
+ {
+ return m_glyphBitmapImage;
+ }
+
+ void Update(Windows::Devices::Enumeration::DeviceInformationUpdate const& deviceInfoUpdate);
+
+ event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
+ void PropertyChanged(event_token const& token) noexcept;
+
+ private:
+ Windows::Devices::Enumeration::DeviceInformation m_deviceInformation{ nullptr };
+ Windows::UI::Xaml::Media::Imaging::BitmapImage m_glyphBitmapImage{ nullptr };
+ event m_propertyChanged;
+
+ fire_and_forget UpdateGlyphBitmapImage();
+ void OnPropertyChanged(param::hstring const& property);
+ bool LookupBooleanProperty(param::hstring const& property);
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct BluetoothLEDeviceDisplay : BluetoothLEDeviceDisplayT
+ {
+ };
+}
diff --git a/Samples/BluetoothLE/cppwinrt/DisplayHelpers.idl b/Samples/BluetoothLE/cppwinrt/DisplayHelpers.idl
new file mode 100644
index 0000000000..f33fb5c2b6
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/DisplayHelpers.idl
@@ -0,0 +1,57 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+namespace SDKTemplate
+{
+ enum AttributeType
+ {
+ Service = 0,
+ Characteristic = 1,
+ Descriptor = 2
+ };
+
+ ///
+ /// Represents the display of an attribute - both characteristics and services.
+ ///
+ runtimeclass BluetoothLEAttributeDisplay
+ {
+ static BluetoothLEAttributeDisplay CreateFromService(Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService service);
+ static BluetoothLEAttributeDisplay CreateFromCharacteristic(Windows.Devices.Bluetooth.GenericAttributeProfile.GattCharacteristic characteristic);
+
+ Windows.Devices.Bluetooth.GenericAttributeProfile.GattCharacteristic characteristic;
+ Windows.Devices.Bluetooth.GenericAttributeProfile.GattDescriptor descriptor;
+ Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService service;
+ String Name{ get; };
+ String AttributeDisplayType{ get; };
+ };
+
+ ///
+ /// Display class used to represent a BluetoothLEDevice in the Device list
+ ///
+ runtimeclass BluetoothLEDeviceDisplay : Windows.UI.Xaml.Data.INotifyPropertyChanged
+ {
+ BluetoothLEDeviceDisplay(Windows.Devices.Enumeration.DeviceInformation deviceInfoIn);
+
+ Windows.Devices.Enumeration.DeviceInformation DeviceInformation{ get; };
+
+ String Id{ get; };
+ String Name{ get; };
+ Boolean IsPaired{ get; };
+ Boolean IsConnected{ get; };
+ Boolean IsConnectable{ get; };
+
+ IMapView Properties{ get; };
+
+ Windows.UI.Xaml.Media.Imaging.BitmapImage GlyphBitmapImage{ get; };
+
+ void Update(Windows.Devices.Enumeration.DeviceInformationUpdate deviceInfoUpdate);
+ };
+}
diff --git a/Samples/BluetoothLE/cppwinrt/Package.appxmanifest b/Samples/BluetoothLE/cppwinrt/Package.appxmanifest
new file mode 100644
index 0000000000..d9191f2864
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/Package.appxmanifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+ BluetoothLE C++/WinRT Sample
+ Microsoft Corporation
+ Assets\storelogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/BluetoothLE/cppwinrt/PresentationFormats.h b/Samples/BluetoothLE/cppwinrt/PresentationFormats.h
new file mode 100644
index 0000000000..701e13da4f
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/PresentationFormats.h
@@ -0,0 +1,165 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::SDKTemplate
+{
+ struct PresentationFormats
+ {
+ ///
+ /// Units are established international standards for the measurement of physical quantities.
+ ///
+ /// Please refer https://www.bluetooth.com/specifications/assigned-numbers/units
+ enum class Units : uint16_t
+ {
+ Unitless = 0x2700,
+ LengthMetre = 0x2701,
+ MassKilogram = 0x2702,
+ TimeSecond = 0x2703,
+ ElectricCurrentAmpere = 0x2704,
+ ThermodynamicTemperatureKelvin = 0x2705,
+ AmountOfSubstanceMole = 0x2706,
+ LuminousIntensityCandela = 0x2707,
+ AreaSquareMetres = 0x2710,
+ VolumeCubicMetres = 0x2711,
+ VelocityMetresPerSecond = 0x2712,
+ AccelerationMetresPerSecondSquared = 0x2713,
+ WaveNumberReciprocalMetre = 0x2714,
+ DensityKilogramperCubicMetre = 0x2715,
+ SurfaceDensityKilogramPerSquareMetre = 0x2716,
+ SpecificVolumeCubicMetrePerKilogram = 0x2717,
+ CurrentDensityAmperePerSquareMetre = 0x2718,
+ MagneticFieldStrengthAmperePerMetre = 0x2719,
+ AmountConcentrationMolePerCubicMetre = 0x271A,
+ MassConcentrationKilogramPerCubicMetre = 0x271B,
+ LuminanceCandelaPerSquareMetre = 0x271C,
+ RefractiveIndex = 0x271D,
+ RelativePermeability = 0x271E,
+ PlaneAngleRadian = 0x2720,
+ SolidAngleSteradian = 0x2721,
+ FrequencyHertz = 0x2722,
+ ForceNewton = 0x2723,
+ PressurePascal = 0x2724,
+ EnergyJoule = 0x2725,
+ PowerWatt = 0x2726,
+ ElectricChargeCoulomb = 0x2727,
+ ElectricPotentialDifferenceVolt = 0x2728,
+ CapacitanceFarad = 0x2729,
+ ElectricResistanceOhm = 0x272A,
+ ElectricConductanceSiemens = 0x272B,
+ MagneticFluxWeber = 0x272C,
+ MagneticFluxDensityTesla = 0x272D,
+ InductanceHenry = 0x272E,
+ CelsiusTemperatureDegreeCelsius = 0x272F,
+ LuminousFluxLumen = 0x2730,
+ IlluminanceLux = 0x2731,
+ ActivityReferredToARadioNuclideBecquerel = 0x2732,
+ AbsorbedDoseGray = 0x2733,
+ DoseEquivalentSievert = 0x2734,
+ CatalyticActivityKatal = 0x2735,
+ DynamicViscosityPascalSecond = 0x2740,
+ MomentOfForceNewtonMetre = 0x2741,
+ SurfaceTensionNewtonPerMetre = 0x2742,
+ AngularVelocityRadianPerSecond = 0x2743,
+ AngularAccelerationRadianPerSecondSquared = 0x2744,
+ HeatFluxDensityWattPerSquareMetre = 0x2745,
+ HeatCapacityJoulePerKelvin = 0x2746,
+ SpecificHeatCapacityJoulePerKilogramKelvin = 0x2747,
+ SpecificEnergyJoulePerKilogram = 0x2748,
+ ThermalConductivityWattPerMetreKelvin = 0x2749,
+ EnergyDensityJoulePerCubicMetre = 0x274A,
+ ElectricfieldstrengthVoltPerMetre = 0x274B,
+ ElectricchargeDensityCoulombPerCubicMetre = 0x274C,
+ SurfacechargeDensityCoulombPerSquareMetre = 0x274D,
+ ElectricFluxDensityCoulombPerSquareMetre = 0x274E,
+ PermittivityFaradPerMetre = 0x274F,
+ PermeabilityHenryPerMetre = 0x2750,
+ MolarEnergyJoulePermole = 0x2751,
+ MolarentropyJoulePermoleKelvin = 0x2752,
+ ExposureCoulombPerKilogram = 0x2753,
+ AbsorbeddoserateGrayPerSecond = 0x2754,
+ RadiantintensityWattPerSteradian = 0x2755,
+ RadianceWattPerSquareMetreSteradian = 0x2756,
+ CatalyticActivityConcentrationKatalPerCubicMetre = 0x2757,
+ TimeMinute = 0x2760,
+ TimeHour = 0x2761,
+ TimeDay = 0x2762,
+ PlaneAngleDegree = 0x2763,
+ PlaneAngleMinute = 0x2764,
+ PlaneAngleSecond = 0x2765,
+ AreaHectare = 0x2766,
+ VolumeLitre = 0x2767,
+ MassTonne = 0x2768,
+ PressureBar = 0x2780,
+ PressureMilliMetreofmercury = 0x2781,
+ LengthAngstrom = 0x2782,
+ LengthNauticalMile = 0x2783,
+ AreaBarn = 0x2784,
+ VelocityKnot = 0x2785,
+ LogarithmicRadioQuantityNeper = 0x2786,
+ LogarithmicRadioQuantityBel = 0x2787,
+ LengthYard = 0x27A0,
+ LengthParsec = 0x27A1,
+ LengthInch = 0x27A2,
+ LengthFoot = 0x27A3,
+ LengthMile = 0x27A4,
+ PressurePoundForcePerSquareinch = 0x27A5,
+ VelocityKiloMetrePerHour = 0x27A6,
+ VelocityMilePerHour = 0x27A7,
+ AngularVelocityRevolutionPerminute = 0x27A8,
+ EnergyGramcalorie = 0x27A9,
+ EnergyKilogramcalorie = 0x27AA,
+ EnergyKiloWattHour = 0x27AB,
+ ThermodynamicTemperatureDegreeFahrenheit = 0x27AC,
+ Percentage = 0x27AD,
+ PerMille = 0x27AE,
+ PeriodBeatsPerMinute = 0x27AF,
+ ElectricchargeAmpereHours = 0x27B0,
+ MassDensityMilligramPerdeciLitre = 0x27B1,
+ MassDensityMillimolePerLitre = 0x27B2,
+ TimeYear = 0x27B3,
+ TimeMonth = 0x27B4,
+ ConcentrationCountPerCubicMetre = 0x27B5,
+ IrradianceWattPerSquareMetre = 0x27B6,
+ MilliliterPerKilogramPerminute = 0x27B7,
+ MassPound = 0x27B8,
+ };
+
+ ///
+ /// The Name Space field is used to identify the organization that is responsible for defining the enumerations for the description field.
+ ///
+ ///
+ /// Please refer https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
+ ///
+ enum class NamespaceId : uint8_t
+ {
+ BluetoothSigAssignedNumber = 1,
+ ReservedForFutureUse,
+ };
+
+ ///
+ /// The Description is an enumerated value from the organization identified by the Name Space field.
+ ///
+ ///
+ /// Please refer https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
+ ///
+ static constexpr uint16_t Description = 0x0000;
+
+ ///
+ /// Exponent value for the characteristics
+ ///
+ static constexpr int Exponent = 0;
+
+ };
+}
+
diff --git a/Samples/BluetoothLE/cppwinrt/SampleConfiguration.cpp b/Samples/BluetoothLE/cppwinrt/SampleConfiguration.cpp
new file mode 100644
index 0000000000..5ffb6c1290
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/SampleConfiguration.cpp
@@ -0,0 +1,43 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "MainPage.h"
+#include "SampleConfiguration.h"
+
+using namespace winrt;
+using namespace SDKTemplate;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::UI::Xaml;
+
+hstring implementation::MainPage::FEATURE_NAME()
+{
+ return L"BluetoothLE C++/WinRT Sample";
+}
+
+IVector implementation::MainPage::scenariosInner = winrt::single_threaded_observable_vector(
+{
+ Scenario{ L"Client: Discover servers", xaml_typename() },
+ Scenario{ L"Client: Connect to a server", xaml_typename() },
+ Scenario{ L"Server: Publish foreground", xaml_typename() },
+});
+
+hstring SampleState::SelectedBleDeviceId;
+hstring SampleState::SelectedBleDeviceName{ L"No device selected" };
+
+Rect winrt::SDKTemplate::GetElementRect(FrameworkElement const& element)
+{
+ auto transform = element.TransformToVisual(nullptr);
+ Point point = transform.TransformPoint({});
+ return { point, { static_cast(element.ActualWidth()), static_cast(element.ActualHeight()) } };
+}
diff --git a/Samples/BluetoothLE/cppwinrt/SampleConfiguration.h b/Samples/BluetoothLE/cppwinrt/SampleConfiguration.h
new file mode 100644
index 0000000000..4930533aff
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/SampleConfiguration.h
@@ -0,0 +1,33 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::SDKTemplate
+{
+ struct Constants
+ {
+ static constexpr guid CalcServiceUuid{ 0xcaecface, 0xe1d9, 0x11e6, { 0xbf, 0x01, 0xfe, 0x55, 0x13, 0x50, 0x34, 0xf0 } }; // {caecface-e1d9-11e6-bf01-fe55135034f0}
+ static constexpr guid Op1CharacteristicUuid{ 0xcaecface, 0xe1d9, 0x11e6, { 0xbf, 0x01, 0xfe, 0x55, 0x13, 0x50, 0x34, 0xf1 } }; // {caecface-e1d9-11e6-bf01-fe55135034f1}
+ static constexpr guid Op2CharacteristicUuid{ 0xcaecface, 0xe1d9, 0x11e6, { 0xbf, 0x01, 0xfe, 0x55, 0x13, 0x50, 0x34, 0xf2 } }; // {caecface-e1d9-11e6-bf01-fe55135034f2}
+ static constexpr guid OperatorCharacteristicUuid{ 0xcaecface, 0xe1d9, 0x11e6, { 0xbf, 0x01, 0xfe, 0x55, 0x13, 0x50, 0x34, 0xf3 } }; // {caecface-e1d9-11e6-bf01-fe55135034f3}
+ static constexpr guid ResultCharacteristicUuid{ 0xcaecface, 0xe1d9, 0x11e6, { 0xbf, 0x01, 0xfe, 0x55, 0x13, 0x50, 0x34, 0xf4 } }; // {caecface-e1d9-11e6-bf01-fe55135034f4}
+ };
+
+ struct SampleState
+ {
+ static hstring SelectedBleDeviceId;
+ static hstring SelectedBleDeviceName;
+ };
+
+ Windows::Foundation::Rect GetElementRect(Windows::UI::Xaml::FrameworkElement const& element);
+}
diff --git a/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.cpp b/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.cpp
new file mode 100644
index 0000000000..d3eff7c080
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.cpp
@@ -0,0 +1,321 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario1_Discovery.h"
+#include "SampleConfiguration.h"
+#include "BluetoothLEDeviceDisplay.h"
+
+using namespace winrt;
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Foundation;
+using namespace Windows::UI::Core;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt
+{
+ hstring to_hstring(DevicePairingResultStatus status)
+ {
+ switch (status)
+ {
+ case DevicePairingResultStatus::Paired: return L"Paired";
+ case DevicePairingResultStatus::NotReadyToPair: return L"NotReadyToPair";
+ case DevicePairingResultStatus::NotPaired: return L"NotPaired";
+ case DevicePairingResultStatus::AlreadyPaired: return L"AlreadyPaired";
+ case DevicePairingResultStatus::ConnectionRejected: return L"ConnectionRejected";
+ case DevicePairingResultStatus::TooManyConnections: return L"TooManyConnections";
+ case DevicePairingResultStatus::HardwareFailure: return L"HardwareFailure";
+ case DevicePairingResultStatus::AuthenticationTimeout: return L"AuthenticationTimeout";
+ case DevicePairingResultStatus::AuthenticationNotAllowed: return L"AuthenticationNotAllowed";
+ case DevicePairingResultStatus::AuthenticationFailure: return L"AuthenticationFailure";
+ case DevicePairingResultStatus::NoSupportedProfiles: return L"NoSupportedProfiles";
+ case DevicePairingResultStatus::ProtectionLevelCouldNotBeMet: return L"ProtectionLevelCouldNotBeMet";
+ case DevicePairingResultStatus::AccessDenied: return L"AccessDenied";
+ case DevicePairingResultStatus::InvalidCeremonyData: return L"InvalidCeremonyData";
+ case DevicePairingResultStatus::PairingCanceled: return L"PairingCanceled";
+ case DevicePairingResultStatus::OperationAlreadyInProgress: return L"OperationAlreadyInProgress";
+ case DevicePairingResultStatus::RequiredHandlerNotRegistered: return L"RequiredHandlerNotRegistered";
+ case DevicePairingResultStatus::RejectedByHandler: return L"RejectedByHandler";
+ case DevicePairingResultStatus::RemoteDeviceHasAssociation: return L"RemoteDeviceHasAssociation";
+ case DevicePairingResultStatus::Failed: return L"Failed";
+ }
+ return L"Code " + to_hstring(static_cast(status));
+ }
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+ // This scenario uses a DeviceWatcher to enumerate nearby Bluetooth Low Energy devices,
+ // displays them in a ListView, and lets the user select a device and pair it.
+ // This device will be used by future scenarios.
+ // For more information about device discovery and pairing, including examples of
+ // customizing the pairing process, see the DeviceEnumerationAndPairing sample.
+
+#pragma region UI Code
+
+ Scenario1_Discovery::Scenario1_Discovery()
+ {
+ InitializeComponent();
+ }
+
+ void Scenario1_Discovery::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ StopBleDeviceWatcher();
+
+ // Save the selected device's ID for use in other scenarios.
+ auto bleDeviceDisplay = ResultsListView().SelectedItem().as();
+ if (bleDeviceDisplay != nullptr)
+ {
+ SampleState::SelectedBleDeviceId = bleDeviceDisplay.Id();
+ SampleState::SelectedBleDeviceName = bleDeviceDisplay.Name();
+ }
+ }
+
+ void Scenario1_Discovery::EnumerateButton_Click()
+ {
+ if (deviceWatcher == nullptr)
+ {
+ StartBleDeviceWatcher();
+ EnumerateButton().Content(box_value(L"Stop enumerating"));
+ rootPage.NotifyUser(L"Device watcher started.", NotifyType::StatusMessage);
+ }
+ else
+ {
+ StopBleDeviceWatcher();
+ EnumerateButton().Content(box_value(L"Start enumerating"));
+ rootPage.NotifyUser(L"Device watcher stopped.", NotifyType::StatusMessage);
+ }
+ }
+#pragma endregion
+
+#pragma region Device discovery
+ ///
+ /// Starts a device watcher that looks for all nearby Bluetooth devices (paired or unpaired).
+ /// Attaches event handlers to populate the device collection.
+ ///
+ void Scenario1_Discovery::StartBleDeviceWatcher()
+ {
+ // Additional properties we would like about the device.
+ // Property strings are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/ff521659(v=vs.85).aspx
+ auto requestedProperties = single_threaded_vector({ L"System.Devices.Aep.DeviceAddress", L"System.Devices.Aep.IsConnected", L"System.Devices.Aep.Bluetooth.Le.IsConnectable" });
+
+ // BT_Code: Example showing paired and non-paired in a single query.
+ hstring aqsAllBluetoothLEDevices = L"(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")";
+
+ deviceWatcher =
+ Windows::Devices::Enumeration::DeviceInformation::CreateWatcher(
+ aqsAllBluetoothLEDevices,
+ requestedProperties,
+ DeviceInformationKind::AssociationEndpoint);
+
+ // Register event handlers before starting the watcher.
+ deviceWatcherAddedToken = deviceWatcher.Added({ get_weak(), &Scenario1_Discovery::DeviceWatcher_Added });
+ deviceWatcherUpdatedToken = deviceWatcher.Updated({ get_weak(), &Scenario1_Discovery::DeviceWatcher_Updated });
+ deviceWatcherRemovedToken = deviceWatcher.Removed({ get_weak(), &Scenario1_Discovery::DeviceWatcher_Removed });
+ deviceWatcherEnumerationCompletedToken = deviceWatcher.EnumerationCompleted({ get_weak(), &Scenario1_Discovery::DeviceWatcher_EnumerationCompleted });
+ deviceWatcherStoppedToken = deviceWatcher.Stopped({ get_weak(), &Scenario1_Discovery::DeviceWatcher_Stopped });
+
+ // Start over with an empty collection.
+ m_knownDevices.Clear();
+
+ // Start the watcher. Active enumeration is limited to approximately 30 seconds.
+ // This limits power usage and reduces interference with other Bluetooth activities.
+ // To monitor for the presence of Bluetooth LE devices for an extended period,
+ // use the BluetoothLEAdvertisementWatcher runtime class. See the BluetoothAdvertisement
+ // sample for an example.
+ deviceWatcher.Start();
+ }
+
+ ///
+ /// Stops watching for all nearby Bluetooth devices.
+ ///
+ void Scenario1_Discovery::StopBleDeviceWatcher()
+ {
+ if (deviceWatcher != nullptr)
+ {
+ // Unregister the event handlers.
+ deviceWatcher.Added(deviceWatcherAddedToken);
+ deviceWatcher.Updated(deviceWatcherUpdatedToken);
+ deviceWatcher.Removed(deviceWatcherRemovedToken);
+ deviceWatcher.EnumerationCompleted(deviceWatcherEnumerationCompletedToken);
+ deviceWatcher.Stopped(deviceWatcherStoppedToken);
+
+ // Stop the watcher.
+ deviceWatcher.Stop();
+ deviceWatcher = nullptr;
+ }
+ }
+
+ std::tuple Scenario1_Discovery::FindBluetoothLEDeviceDisplay(hstring const& id)
+ {
+ uint32_t size = m_knownDevices.Size();
+ for (uint32_t index = 0; index < size; index++)
+ {
+ auto bleDeviceDisplay = m_knownDevices.GetAt(index).as();
+ if (bleDeviceDisplay.Id() == id)
+ {
+ return { bleDeviceDisplay, index };
+ }
+ }
+ return { nullptr, 0-1U };
+ }
+
+ std::vector::iterator Scenario1_Discovery::FindUnknownDevices(hstring const& id)
+ {
+ return std::find_if(UnknownDevices.begin(), UnknownDevices.end(), [&](auto&& bleDeviceInfo)
+ {
+ return bleDeviceInfo.Id() == id;
+ });
+ }
+
+ fire_and_forget Scenario1_Discovery::DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo)
+ {
+ // We must update the collection on the UI thread because the collection is databound to a UI element.
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ OutputDebugStringW((L"Added " + deviceInfo.Id() + deviceInfo.Name()).c_str());
+
+ // Protect against race condition if the task runs after the app stopped the deviceWatcher.
+ if (sender == deviceWatcher)
+ {
+ // Make sure device isn't already present in the list.
+ if (std::get<0>(FindBluetoothLEDeviceDisplay(deviceInfo.Id())) == nullptr)
+ {
+ if (!deviceInfo.Name().empty())
+ {
+ // If device has a friendly name display it immediately.
+ m_knownDevices.Append(make(deviceInfo));
+ }
+ else
+ {
+ // Add it to a list in case the name gets updated later.
+ UnknownDevices.push_back(deviceInfo);
+ }
+ }
+ }
+ }
+
+ fire_and_forget Scenario1_Discovery::DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate)
+ {
+ // We must update the collection on the UI thread because the collection is databound to a UI element.
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ OutputDebugStringW((L"Updated " + deviceInfoUpdate.Id()).c_str());
+
+ // Protect against race condition if the task runs after the app stopped the deviceWatcher.
+ if (sender == deviceWatcher)
+ {
+ SDKTemplate::BluetoothLEDeviceDisplay bleDeviceDisplay = std::get<0>(FindBluetoothLEDeviceDisplay(deviceInfoUpdate.Id()));
+ if (bleDeviceDisplay != nullptr)
+ {
+ // Device is already being displayed - update UX.
+ bleDeviceDisplay.Update(deviceInfoUpdate);
+ co_return;
+ }
+
+ auto deviceInfo = FindUnknownDevices(deviceInfoUpdate.Id());
+ if (deviceInfo != UnknownDevices.end())
+ {
+ deviceInfo->Update(deviceInfoUpdate);
+ // If device has been updated with a friendly name it's no longer unknown.
+ if (!deviceInfo->Name().empty())
+ {
+ m_knownDevices.Append(make(*deviceInfo));
+ UnknownDevices.erase(deviceInfo);
+ }
+ }
+ }
+ }
+
+ fire_and_forget Scenario1_Discovery::DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate)
+ {
+ // We must update the collection on the UI thread because the collection is databound to a UI element.
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ OutputDebugStringW((L"Removed " + deviceInfoUpdate.Id()).c_str());
+
+ // Protect against race condition if the task runs after the app stopped the deviceWatcher.
+ if (sender == deviceWatcher)
+ {
+ // Find the corresponding DeviceInformation in the collection and remove it.
+ auto[bleDeviceDisplay, index] = FindBluetoothLEDeviceDisplay(deviceInfoUpdate.Id());
+ if (bleDeviceDisplay != nullptr)
+ {
+ m_knownDevices.RemoveAt(index);
+ }
+
+ auto deviceInfo = FindUnknownDevices(deviceInfoUpdate.Id());
+ if (deviceInfo != UnknownDevices.end())
+ {
+ UnknownDevices.erase(deviceInfo);
+ }
+ }
+ }
+
+ fire_and_forget Scenario1_Discovery::DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, IInspectable const&)
+ {
+ // Access this->deviceWatcher on the UI thread to avoid race conditions.
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ // Protect against race condition if the task runs after the app stopped the deviceWatcher.
+ if (sender == deviceWatcher)
+ {
+ rootPage.NotifyUser(to_hstring(m_knownDevices.Size()) + L" devices found. Enumeration completed.",
+ NotifyType::StatusMessage);
+ }
+ }
+
+ fire_and_forget Scenario1_Discovery::DeviceWatcher_Stopped(DeviceWatcher sender, IInspectable const&)
+ {
+ // Access this->deviceWatcher on the UI thread to avoid race conditions.
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ // Protect against race condition if the task runs after the app stopped the deviceWatcher.
+ if (sender == deviceWatcher)
+ {
+ rootPage.NotifyUser(L"No longer watching for devices.",
+ sender.Status() == DeviceWatcherStatus::Aborted ? NotifyType::ErrorMessage : NotifyType::StatusMessage);
+ }
+ }
+#pragma endregion
+
+#pragma region Pairing
+ fire_and_forget Scenario1_Discovery::PairButton_Click()
+ {
+ auto lifetime = get_strong();
+ EnumerateButton().IsEnabled(false);
+
+ rootPage.NotifyUser(L"Pairing started. Please wait...", NotifyType::StatusMessage);
+
+ // For more information about device pairing, including examples of
+ // customizing the pairing process, see the DeviceEnumerationAndPairing sample.
+
+ // Capture the current selected item in case the user changes it while we are pairing.
+ auto bleDeviceDisplay = ResultsListView().SelectedItem().as();
+
+ // BT_Code: Pair the currently selected device.
+ DevicePairingResult result = co_await bleDeviceDisplay.DeviceInformation().Pairing().PairAsync();
+ DevicePairingResultStatus status = result.Status();
+ rootPage.NotifyUser(L"Pairing result = " + to_hstring(status),
+ status == DevicePairingResultStatus::Paired || status == DevicePairingResultStatus::AlreadyPaired
+ ? NotifyType::StatusMessage
+ : NotifyType::ErrorMessage);
+
+ EnumerateButton().IsEnabled(true);
+ }
+#pragma endregion
+}
diff --git a/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.h b/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.h
new file mode 100644
index 0000000000..aa1084260a
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.h
@@ -0,0 +1,63 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario1_Discovery.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario1_Discovery : Scenario1_DiscoveryT
+ {
+ Scenario1_Discovery();
+
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+
+ Windows::Foundation::Collections::IObservableVector KnownDevices()
+ {
+ return m_knownDevices;
+ }
+
+ void EnumerateButton_Click();
+ fire_and_forget PairButton_Click();
+ bool Not(bool value) { return !value; }
+
+ private:
+ SDKTemplate::MainPage rootPage{ SDKTemplate::implementation::MainPage::Current() };
+ Windows::Foundation::Collections::IObservableVector m_knownDevices = single_threaded_observable_vector();
+ std::vector UnknownDevices;
+ Windows::Devices::Enumeration::DeviceWatcher deviceWatcher{ nullptr };
+ event_token deviceWatcherAddedToken;
+ event_token deviceWatcherUpdatedToken;
+ event_token deviceWatcherRemovedToken;
+ event_token deviceWatcherEnumerationCompletedToken;
+ event_token deviceWatcherStoppedToken;
+
+ void StartBleDeviceWatcher();
+ void StopBleDeviceWatcher();
+ std::tuple FindBluetoothLEDeviceDisplay(hstring const& id);
+ std::vector::iterator FindUnknownDevices(hstring const& id);
+
+ fire_and_forget DeviceWatcher_Added(Windows::Devices::Enumeration::DeviceWatcher sender, Windows::Devices::Enumeration::DeviceInformation deviceInfo);
+ fire_and_forget DeviceWatcher_Updated(Windows::Devices::Enumeration::DeviceWatcher sender, Windows::Devices::Enumeration::DeviceInformationUpdate deviceInfoUpdate);
+ fire_and_forget DeviceWatcher_Removed(Windows::Devices::Enumeration::DeviceWatcher sender, Windows::Devices::Enumeration::DeviceInformationUpdate deviceInfoUpdate);
+ fire_and_forget DeviceWatcher_EnumerationCompleted(Windows::Devices::Enumeration::DeviceWatcher sender, Windows::Foundation::IInspectable const&);
+ fire_and_forget DeviceWatcher_Stopped(Windows::Devices::Enumeration::DeviceWatcher sender, Windows::Foundation::IInspectable const&);
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario1_Discovery : Scenario1_DiscoveryT
+ {
+ };
+}
diff --git a/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.idl b/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.idl
new file mode 100644
index 0000000000..c64c88eb56
--- /dev/null
+++ b/Samples/BluetoothLE/cppwinrt/Scenario1_Discovery.idl
@@ -0,0 +1,26 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+namespace SDKTemplate
+{
+ [default_interface]
+ runtimeclass Scenario1_Discovery : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario1_Discovery();
+
+ Windows.Foundation.Collections.IObservableVector