diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..5aec15cdd7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,37 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +# Declare files that will always have CRLF line endings on checkout. +*.appxmanifest text eol=crlf +*.c text eol=crlf +*.cpp text eol=crlf +*.cs text eol=crlf +*.csproj text eol=crlf +*.css text eol=crlf +*.def text eol=crlf +*.filters text eol=crlf +*.h text eol=crlf +*.htm text eol=crlf +*.html text eol=crlf +*.idl text eol=crlf +*.inf text eol=crlf +*.inx text eol=crlf +*.js text eol=crlf +*.jsproj text eol=crlf +*.rc text eol=crlf +*.rgs text eol=crlf +*.sln text eol=crlf +*.vcxproj text eol=crlf +*.xaml text eol=crlf + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +*.cs diff=csharp + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..677dfa66c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,201 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +[Gg]enerated Files/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studo 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.[Cc]ache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Custom ignores +gallery.xml +project.lock.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..701b833021 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..37876aaebb --- /dev/null +++ b/README.md @@ -0,0 +1,457 @@ +# Universal Windows app samples +This repo contains the samples that demonstrate the API usage patterns for the Universal Windows Platform (UWP) in the Windows Software Development Kit (SDK) for Windows 10. These code samples were created with the Universal Windows templates available in Visual Studio, and are designed to run on desktop, mobile, and future devices that support the Universal Windows Platform. + +## Universal Windows Platform development +These samples require Visual Studio 2015 and the Windows Software Development Kit (SDK) for Windows 10 to build, test, and deploy your Universal Windows apps. + + [Get a free copy of Visual Studio 2015 Community Edition with support for building Universal Windows apps](http://go.microsoft.com/fwlink/?LinkID=280676) + +Additionally, to stay on top of the latest updates to Windows and the development tools, become a Windows Insider by joining the Windows Insider Program. + + [Become a Windows Insider](https://insider.windows.com/) + +## Using the samples +The easiest way to use these samples without using Git is to download the zip file containing the current version (using the link below or by clicking the "Download ZIP" button on the repo page). You can then unzip the samples and use them in Visual Studio 2015. + + [Download the samples ZIP](../../archive/master.zip) + +The samples use Linked files in Visual Studio to reduce duplication of common files, including sample template files and image assets. These common files are stored in the SharedContent folder at the root of the repository and referred to in the project files using links. + +For more info about the programming models, platforms, languages, and APIs demonstrated in these samples, please refer to the guidance, tutorials, and reference topics provided in the Windows 10 documentation available in the [Windows Developer Center](https://dev.windows.com). These samples are provided as-is in order to indicate or demonstrate the functionality of the programming models and feature APIs for Windows. + +## Contributions +These samples are direct from the feature teams and we welcome your input on issues and suggestions for new samples. At this time we are not accepting new samples from the public, but check back here as we evolve our contribution model. + +## Samples by category + + + + + + + + + +
App settings
App package informationApplication data
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Audio, video, and camera
Adaptive streamingAdvanced castingAudio categories
Audio graphsBackground audioBasic media casting
Camera face detectionCamera preview frameHigh dynamic range
Camera profilesBasic camera appVideo stabilization
Direct2D photo adjustmentDASH streamingMedia editing
Media transport controlsMIDIBasic face detection
Basic face trackingSimple imagingSpatial audio
System media transport controlsTranscoding mediaVideo playback
Windows audio session (WASAPI)Windows media import
+ + + + + + + + + + + + +
Communications
Phone callReal-time communicationSMS send and receive
Voice over IP (VoIP)
+ + + + + + + + +
Contacts and calendar
Appointment calendarUserDataAccountManager
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Controls, layout, and text
AutoSuggestBox migrationClipboardContext menu
Context menu (XAML)Downloadable fonts (DirectWrite)Line spacing (DirectWrite)
Focus visualsFull screen modeHTML WebView control
ListView and GridViewLock screen appsMessage dialog
Multiple viewsOCRPrinting
Pull to refreshWindow resizingScaling according to DPI
Splash screenState triggersTitle bar
Disabling selectionUser interaction modeCommanding
Downloadable fonts (XAML)Responsiveness techniquesTailored multiple views
XAML UI basics
+ + + + + + + + + + + + + +
Custom user interactions
Basic inputComplex inkingInking
Low latency inputSimple inking
+ + + + + + + + + + + + + + + + + + + + + + + +
Data
CompressionContent indexerHTML5 form validation
IndexedDBLoggingSerializing and deserializing data
Blobsx:Bindx:DeferLoadStrategy
XML DOMXmlLite
+ + + + + + + + + +
Deep links and app-to-app communication
App servicesSharing content source appSharing content target app
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Devices and sensors
AccelerometerActivity detection sensorAllJoyn consumer experiences
AllJoyn producer experiencesAltimeterBackground sensors
Barcode scannerBarometerBluetooth advertisement
Cash drawerCompassCustom HID device
Custom sensorsCustom serial deviceCustom USB device
Device enumerationInclinometerLamp device
GyrometerMagnetic stripe readerNear field communication (NFC)
Light sensorOrientation sensorPedometer
NFC enterprise provisionerProximity sensorRelative inclinometer
POS printerSerial ArduinoSimple orientation sensor
Relative orientation sensor
+ + + + + + + + + + + + + + + + + + + +
Files, folders, and libraries
File accessFile and folder thumbnailFile picker provider
File pickerFolder enumerationHomeGroup
Library managementFile searchSemantic text query
+ + + + + + + + +
Gaming
Direct3D gameDirectX and XAML game
+ + + + + + + + + + + + + + + + + + +
Globalization and localization
Application resources and localizationJapanese phonetic analysisLanguage font mapping
Linguistic servicesNumber formatting and parsingText segmentation
Text suggestionsUnicode string processing
+ + + + + + + + + + + + + + + + + +
Graphics and animation
Animation metricsDirect2D custom image effectsDirect2D gradient mesh
HTML animation libraryTransform3D animationsTransform3D parallax
Efficient HTML animations
+ + + + + + + + + + + + + + + + + + + + + + +
Identity, security, and encryption
Account picture nameCredential lockerCredential picker
Enterprise data protectionKeyCredentialManagerLock screen personalization
Smart cardsUserConsentVerifierWeb account management
WebAuthenticationBroker
+ + + + + + + + +
Launching and background tasks
Association launchingBackground task
+ + + + + + + + + +
Maps and location
GeolocationGeotagMapControl
+ + + + + + + + + + + + + +
Navigation
Master/detailPivotProjection
XAML navigation menuXHR, handling navigation errors, and URL schemes
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Networking and web services
Background transferDatagramSocketExchange Active Sync (EAS)
RSS reader end-to-end sampleHttpClientJSON
Mobile broadbandRadiosSocket activity trigger stream socket
StreamSocketSyndicationUSSD protocol
WebSocketWi-Fi DirectWi-Fi Direct Services
Wi-Fi scanningXHR, handling navigation errors, and URL schemes
+ + + + + + + + + +
Platform architecture
In-process component authoringOut-of-process component authoringIn-process component proxy/stub generation
+ + + + + + + + +
Speech and Cortana
Cortana voice commandSpeech recognition and synthesis
+ + + + + + + +
Threading
JavaScript Web Workers app multithreading
+ + + + + + + + +
Tiles, toasts, and notifications
BadgeSecondary tiles
\ No newline at end of file diff --git a/Samples/Accelerometer/README.md b/Samples/Accelerometer/README.md new file mode 100644 index 0000000000..4c5b435a4e --- /dev/null +++ b/Samples/Accelerometer/README.md @@ -0,0 +1,72 @@ + + +# Accelerometer sample + +This sample shows how to use the [**Accelerometer**](http://msdn.microsoft.com/library/windows/apps/br225687) API. + +This sample allows the user to view the acceleration forces along the X-, Y-, and Z-axes for a 3-axis accelerometer. You can choose one of four scenarios: + +- Accelerometer data events +- Accelerometer shake events +- Poll accelerometer readings +- Accelerometer orientation changed +- Accelerometer data events batching + +### Acclerometer Data Events + +When you choose the **Enable** button for the **Data Events** option, the app begins streaming accelerometer readings in real time. + +### Accelerometer Shake Events + +When you choose the **Enable** button for the **Shake Events** option, the app displays the cumulative number of shake events each time an event occurs. (The app first increments the event count and then renders the most recent value.) + +### Poll Accelerometer Readings + +When you choose the **Enable** button for the **Polling** option, the app will retrieve the sensor readings at a fixed interval. + +### Accelerometer Orientation Changed + +When you choose the **Enable** button for the **OrientationChange** option, the app will display both raw sensor readings, as well as sensor readings that align with the current display orientation. + +### Accelerometer data events batching** + +When you choose the **Enable** button for the **Data Events** option, the app begins streaming accelerometer readings. The readings may be delivered in batches if the device supports data batching. + +## Related topics + +[**Accelerometer.GetCurrentReading method**](http://msdn.microsoft.com/library/windows/apps/br225699) + +[**Accelerometer.ReadingChanged event handler**](http://msdn.microsoft.com/library/windows/apps/br225702) + +[Quickstart: Responding to user movement with the accelerometer](http://msdn.microsoft.com/library/windows/apps/hh465265) + +[Windows.Devices.Sensors namespace](http://go.microsoft.com/fwlink/p/?linkid=241981) + +## System requirements + +**Client:** Windows 10 + +**Server:** Windows Server 2016 Technical Preview + +**Phone:** Windows 10 + +## Build the sample + +1. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**. +2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the language you desire - either C++ or C\#. Double-click the Visual Studio 2015 Solution (.sln) file. +3. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**. + +## Run the sample + +The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it. + +### Deploying the sample + +- Select Build > Deploy Solution. + +### Deploying and running the sample + +- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or selectDebug > Start Without Debugging. + diff --git a/Samples/Accelerometer/cpp/Accelerometer.sln b/Samples/Accelerometer/cpp/Accelerometer.sln new file mode 100644 index 0000000000..10f2a8c0a7 --- /dev/null +++ b/Samples/Accelerometer/cpp/Accelerometer.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22418.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Accelerometer", "Accelerometer.vcxproj", "{F710B9FD-4E6B-42D7-A99A-6D48888D48B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|ARM.ActiveCfg = Debug|ARM + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|ARM.Build.0 = Debug|ARM + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|ARM.Deploy.0 = Debug|ARM + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|Win32.ActiveCfg = Debug|Win32 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|Win32.Build.0 = Debug|Win32 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|Win32.Deploy.0 = Debug|Win32 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|x64.ActiveCfg = Debug|x64 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|x64.Build.0 = Debug|x64 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Debug|x64.Deploy.0 = Debug|x64 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|ARM.ActiveCfg = Release|ARM + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|ARM.Build.0 = Release|ARM + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|ARM.Deploy.0 = Release|ARM + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|Win32.ActiveCfg = Release|Win32 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|Win32.Build.0 = Release|Win32 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|Win32.Deploy.0 = Release|Win32 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|x64.ActiveCfg = Release|x64 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|x64.Build.0 = Release|x64 + {F710B9FD-4E6B-42D7-A99A-6D48888D48B0}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/Accelerometer/cpp/Accelerometer.vcxproj b/Samples/Accelerometer/cpp/Accelerometer.vcxproj new file mode 100644 index 0000000000..06afcf347e --- /dev/null +++ b/Samples/Accelerometer/cpp/Accelerometer.vcxproj @@ -0,0 +1,243 @@ + + + + {f710b9fd-4e6b-42d7-a99a-6d48888d48b0} + SDKTemplate + en-US + 14.0 + true + Windows Store + 10.0 + 10.0.10240.0 + 10.0.10240.0 + true + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + Application + true + v140 + + + Application + true + v140 + + + Application + true + v140 + + + Application + false + true + v140 + true + + + Application + false + true + v140 + true + + + Application + false + true + v140 + true + + + + + + + + + + + + + + + + + + + + + + + + + $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\..\SharedContent\cpp + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + + ..\..\..\SharedContent\xaml\App.xaml + + + ..\..\..\SharedContent\cpp\MainPage.xaml + + + + Scenario1_DataEvents.xaml + + + Scenario2_ShakeEvents.xaml + + + Scenario3_Polling.xaml + + + Scenario4_OrientationChanged.xaml + + + Scenario5_DataEventsBatching.xaml + + + + + Designer + + + Designer + + + + + + + + Styles\Styles.xaml + + + + + Designer + + + + + ..\..\..\SharedContent\xaml\App.xaml + + + ..\..\..\SharedContent\cpp\MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + Scenario1_DataEvents.xaml + + + Scenario2_ShakeEvents.xaml + + + Scenario3_Polling.xaml + + + Scenario4_OrientationChanged.xaml + + + Scenario5_DataEventsBatching.xaml + + + + + 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 + + + + + + \ No newline at end of file diff --git a/Samples/Accelerometer/cpp/Accelerometer.vcxproj.filters b/Samples/Accelerometer/cpp/Accelerometer.vcxproj.filters new file mode 100644 index 0000000000..dbb5bd5576 --- /dev/null +++ b/Samples/Accelerometer/cpp/Accelerometer.vcxproj.filters @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + + + + + + + + + + Styles + + + + + {3d69c7fe-172e-4737-a906-6b0e1b47f307} + + + {d6ad62a9-d6a8-4fe4-954b-07e844f1033d} + + + \ No newline at end of file diff --git a/Samples/Accelerometer/cpp/Package.appxmanifest b/Samples/Accelerometer/cpp/Package.appxmanifest new file mode 100644 index 0000000000..7302b04421 --- /dev/null +++ b/Samples/Accelerometer/cpp/Package.appxmanifest @@ -0,0 +1,53 @@ + + + + + + + + + + AccelerometerCPP + Microsoft Corporation + Assets\StoreLogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/Accelerometer/cpp/SampleConfiguration.cpp b/Samples/Accelerometer/cpp/SampleConfiguration.cpp new file mode 100644 index 0000000000..ee6898a5d7 --- /dev/null +++ b/Samples/Accelerometer/cpp/SampleConfiguration.cpp @@ -0,0 +1,25 @@ +//********************************************************* +// +// 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 "MainPage.xaml.h" +#include "SampleConfiguration.h" + +using namespace SDKTemplate; + +Platform::Array^ MainPage::scenariosInner = ref new Platform::Array +{ + { "Data Events", "SDKTemplate.Scenario1_DataEvents" }, + { "Shake Events", "SDKTemplate.Scenario2_ShakeEvents" }, + { "Polling", "SDKTemplate.Scenario3_Polling" }, + { "OrientationChanged", "SDKTemplate.Scenario4_OrientationChanged" }, + { "Data Events Batching", "SDKTemplate.Scenario5_DataEventsBatching" } +}; diff --git a/Samples/Accelerometer/cpp/SampleConfiguration.h b/Samples/Accelerometer/cpp/SampleConfiguration.h new file mode 100644 index 0000000000..d5054996a4 --- /dev/null +++ b/Samples/Accelerometer/cpp/SampleConfiguration.h @@ -0,0 +1,47 @@ +//********************************************************* +// +// 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 SDKTemplate +{ + value struct Scenario; + + partial ref class MainPage + { + internal: + static property Platform::String^ FEATURE_NAME + { + Platform::String^ get() + { + return "Accelerometer"; + } + } + + static property Platform::Array^ scenarios + { + Platform::Array^ get() + { + return scenariosInner; + } + } + + private: + static Platform::Array^ scenariosInner; + }; + + public value struct Scenario + { + Platform::String^ Title; + Platform::String^ ClassName; + }; +} diff --git a/Samples/Accelerometer/cpp/Scenario1_DataEvents.xaml b/Samples/Accelerometer/cpp/Scenario1_DataEvents.xaml new file mode 100644 index 0000000000..483c7c04fc --- /dev/null +++ b/Samples/Accelerometer/cpp/Scenario1_DataEvents.xaml @@ -0,0 +1,47 @@ + + + + + + + + +
+
+ +
+ X: no data +
Y: no data +
Z: no data +
+
+ + + \ No newline at end of file diff --git a/Samples/Accelerometer/js/html/scenario2_ShakeEvents.html b/Samples/Accelerometer/js/html/scenario2_ShakeEvents.html new file mode 100644 index 0000000000..40be33c413 --- /dev/null +++ b/Samples/Accelerometer/js/html/scenario2_ShakeEvents.html @@ -0,0 +1,27 @@ + + + + + + + + + + + +
+

+ Registers an event listener for accelerometer shake events and displays the cumulative count of shake events. +

+ + +
+
+ Shake count: 0 +
+
+ + + \ No newline at end of file diff --git a/Samples/Accelerometer/js/html/scenario3_Polling.html b/Samples/Accelerometer/js/html/scenario3_Polling.html new file mode 100644 index 0000000000..84ae67f96b --- /dev/null +++ b/Samples/Accelerometer/js/html/scenario3_Polling.html @@ -0,0 +1,29 @@ + + + + + + + + + + + +
+

Polls for accelerometer data and displays the X, Y and Z acceleration values at a set interval.

+ + +
+
+
+
+ X: no data +
Y: no data +
Z: no data +
+
+ + + \ No newline at end of file diff --git a/Samples/Accelerometer/js/html/scenario4_OrientationChanged.html b/Samples/Accelerometer/js/html/scenario4_OrientationChanged.html new file mode 100644 index 0000000000..f89d331eee --- /dev/null +++ b/Samples/Accelerometer/js/html/scenario4_OrientationChanged.html @@ -0,0 +1,49 @@ + + + + + + + + + + + +
+

+ Registers for OrientationChanged event of the DisplayInformation class to illustrate the usage of the 'ReadingTransform' Property. Displays accelerometer readings with and without the transformation. +

+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Transform:NoneDisplayOrientation
X:no datano data
Y:no datano data
Z:no datano data
+
+ + + \ No newline at end of file diff --git a/Samples/Accelerometer/js/html/scenario5_DataEventsBatching.html b/Samples/Accelerometer/js/html/scenario5_DataEventsBatching.html new file mode 100644 index 0000000000..c84176b0f6 --- /dev/null +++ b/Samples/Accelerometer/js/html/scenario5_DataEventsBatching.html @@ -0,0 +1,31 @@ + + + + + + + + + + + +
+

+ Registers an event listener for accelerometer data (with a report latency specified) and displays the X, Y and Z acceleration values as they are reported. +

+ + +
+
+
+
+ X: no data +
Y: no data +
Z: no data +
+
+ + + \ No newline at end of file diff --git a/Samples/Accelerometer/js/js/sample-configuration.js b/Samples/Accelerometer/js/js/sample-configuration.js new file mode 100644 index 0000000000..c5eef00d34 --- /dev/null +++ b/Samples/Accelerometer/js/js/sample-configuration.js @@ -0,0 +1,20 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + + var sampleTitle = "AccelerometerJS"; + + var scenarios = [ + { url: "/html/scenario1_DataEvents.html", title: "Data Events" }, + { url: "/html/scenario2_ShakeEvents.html", title: "Shake Events" }, + { url: "/html/scenario3_Polling.html", title: "Polling" }, + { url: "/html/scenario4_OrientationChanged.html", title: "OrientationChanged Handling" }, + { url: "/html/scenario5_DataEventsBatching.html", title: "Data Events Batching" } + ]; + + WinJS.Namespace.define("SdkSample", { + sampleTitle: sampleTitle, + scenarios: new WinJS.Binding.List(scenarios) + }); +})(); \ No newline at end of file diff --git a/Samples/Accelerometer/js/js/scenario1_DataEvents.js b/Samples/Accelerometer/js/js/scenario1_DataEvents.js new file mode 100644 index 0000000000..5a55579353 --- /dev/null +++ b/Samples/Accelerometer/js/js/scenario1_DataEvents.js @@ -0,0 +1,90 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var reportInterval = 0; + var accelerometer; + + var page = WinJS.UI.Pages.define("/html/scenario1_DataEvents.html", { + ready: function (element, options) { + document.getElementById("scenario1Open").addEventListener("click", enableReadingChangedScenario, false); + document.getElementById("scenario1Revoke").addEventListener("click", disableReadingChangedScenario, false); + document.getElementById("scenario1Open").disabled = false; + document.getElementById("scenario1Revoke").disabled = true; + + accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault(); + if (accelerometer) { + // Select a report interval that is both suitable for the purposes of the app and supported by the sensor. + // This value will be used later to activate the sensor. + var minimumReportInterval = accelerometer.minimumReportInterval; + reportInterval = minimumReportInterval > 16 ? minimumReportInterval : 16; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + }, + unload: function () { + if (document.getElementById("scenario1Open").disabled) { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.removeEventListener("readingchanged", onDataChanged); + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometer.reportInterval = 0; + } + } + }); + + function visibilityChangeHandler() { + // This is the event handler for VisibilityChanged events. You would register for these notifications + // if handling sensor data when the app is not visible could cause unintended actions in the app. + if (document.getElementById("scenario1Open").disabled) { + if (document.msVisibilityState === "visible") { + // Re-enable sensor input. No need to restore the desired reportInterval (it is restored for us upon app resume) + accelerometer.addEventListener("readingchanged", onDataChanged); + } else { + // Disable sensor input. No need to restore the default reportInterval (resources will be released upon app suspension) + accelerometer.removeEventListener("readingchanged", onDataChanged); + } + } + } + + function onDataChanged(e) { + var reading = e.reading; + + // event can still be in queue after unload is called + // so check if elements are still loaded + + if (document.getElementById("eventOutputX")) { + document.getElementById("eventOutputX").innerHTML = reading.accelerationX.toFixed(2); + } + if (document.getElementById("eventOutputY")) { + document.getElementById("eventOutputY").innerHTML = reading.accelerationY.toFixed(2); + } + if (document.getElementById("eventOutputZ")) { + document.getElementById("eventOutputZ").innerHTML = reading.accelerationZ.toFixed(2); + } + } + + function enableReadingChangedScenario() { + if (accelerometer) { + // Set the reportInterval to enable the sensor events + accelerometer.reportInterval = reportInterval; + + document.addEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.addEventListener("readingchanged", onDataChanged); + document.getElementById("scenario1Open").disabled = true; + document.getElementById("scenario1Revoke").disabled = false; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + } + + function disableReadingChangedScenario() { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.removeEventListener("readingchanged", onDataChanged); + document.getElementById("scenario1Open").disabled = false; + document.getElementById("scenario1Revoke").disabled = true; + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometer.reportInterval = 0; + } +})(); diff --git a/Samples/Accelerometer/js/js/scenario2_ShakeEvents.js b/Samples/Accelerometer/js/js/scenario2_ShakeEvents.js new file mode 100644 index 0000000000..7bca2f0bba --- /dev/null +++ b/Samples/Accelerometer/js/js/scenario2_ShakeEvents.js @@ -0,0 +1,67 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var accelerometer; + + var page = WinJS.UI.Pages.define("/html/scenario2_ShakeEvents.html", { + ready: function (element, options) { + document.getElementById("scenario2Open").addEventListener("click", enableShakenScenario, false); + document.getElementById("scenario2Revoke").addEventListener("click", disableShakenScenario, false); + document.getElementById("scenario2Open").disabled = false; + document.getElementById("scenario2Revoke").disabled = true; + + accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault(); + if (accelerometer === null) { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + }, + unload: function () { + if (document.getElementById("scenario2Open").disabled) { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.removeEventListener("shaken", onShaken); + } + } + }); + + function visibilityChangeHandler() { + // This is the event handler for VisibilityChanged events. You would register for these notifications + // if handling sensor data when the app is not visible could cause unintended actions in the app. + if (document.getElementById("scenario2Open").disabled) { + if (document.msVisibilityState === "visible") { + // Re-enable sensor input + accelerometer.addEventListener("shaken", onShaken); + } else { + // Disable sensor input + accelerometer.removeEventListener("shaken", onShaken); + } + } + } + + var onShaken = (function () { + var shakeCount = 0; + + return function (e) { + shakeCount++; + document.getElementById("shakeOutput").innerHTML = shakeCount; + }; + })(); + + function enableShakenScenario() { + if (accelerometer) { + document.addEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.addEventListener("shaken", onShaken); + document.getElementById("scenario2Open").disabled = true; + document.getElementById("scenario2Revoke").disabled = false; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + } + + function disableShakenScenario() { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.removeEventListener("shaken", onShaken); + document.getElementById("scenario2Open").disabled = false; + document.getElementById("scenario2Revoke").disabled = true; + } +})(); diff --git a/Samples/Accelerometer/js/js/scenario3_Polling.js b/Samples/Accelerometer/js/js/scenario3_Polling.js new file mode 100644 index 0000000000..07bab9022b --- /dev/null +++ b/Samples/Accelerometer/js/js/scenario3_Polling.js @@ -0,0 +1,83 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var reportInterval = 0; + var intervalId = 0; + var accelerometer; + + var page = WinJS.UI.Pages.define("/html/scenario3_Polling.html", { + ready: function (element, options) { + document.getElementById("scenario3Open").addEventListener("click", enableGetReadingScenario, false); + document.getElementById("scenario3Revoke").addEventListener("click", disableGetReadingScenario, false); + document.getElementById("scenario3Open").disabled = false; + document.getElementById("scenario3Revoke").disabled = true; + + accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault(); + if (accelerometer) { + // Select a report interval that is both suitable for the purposes of the app and supported by the sensor. + // This value will be used later to activate the sensor. + var minimumReportInterval = accelerometer.minimumReportInterval; + reportInterval = minimumReportInterval > 16 ? minimumReportInterval : 16; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + }, + unload: function () { + if (document.getElementById("scenario3Open").disabled) { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + clearInterval(intervalId); + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometer.reportInterval = 0; + } + } + }); + + function visibilityChangeHandler() { + // This is the event handler for VisibilityChanged events. You would register for these notifications + // if handling sensor data when the app is not visible could cause unintended actions in the app. + if (document.getElementById("scenario3Open").disabled) { + if (document.msVisibilityState === "visible") { + // Re-enable sensor input. No need to restore the desired reportInterval (it is restored for us upon app resume) + intervalId = setInterval(getCurrentReading, reportInterval); + } else { + // Disable sensor input. No need to restore the default reportInterval (resources will be released upon app suspension) + clearInterval(intervalId); + } + } + } + + function getCurrentReading() { + var reading = accelerometer.getCurrentReading(); + if (reading) { + document.getElementById("readingOutputX").innerHTML = reading.accelerationX.toFixed(2); + document.getElementById("readingOutputY").innerHTML = reading.accelerationY.toFixed(2); + document.getElementById("readingOutputZ").innerHTML = reading.accelerationZ.toFixed(2); + } + } + + function enableGetReadingScenario() { + if (accelerometer) { + // Set the report interval to enable the sensor for polling + accelerometer.reportInterval = reportInterval; + + document.addEventListener("visibilitychange", visibilityChangeHandler, false); + intervalId = setInterval(getCurrentReading, reportInterval); + document.getElementById("scenario3Open").disabled = true; + document.getElementById("scenario3Revoke").disabled = false; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + } + + function disableGetReadingScenario() { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + clearInterval(intervalId); + document.getElementById("scenario3Open").disabled = false; + document.getElementById("scenario3Revoke").disabled = true; + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometer.reportInterval = 0; + } +})(); diff --git a/Samples/Accelerometer/js/js/scenario4_OrientationChanged.js b/Samples/Accelerometer/js/js/scenario4_OrientationChanged.js new file mode 100644 index 0000000000..1996fc8121 --- /dev/null +++ b/Samples/Accelerometer/js/js/scenario4_OrientationChanged.js @@ -0,0 +1,131 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var accelerometerOriginal; + var accelerometerReadingTransform; + var displayInformation; + + var page = WinJS.UI.Pages.define("/html/scenario4_OrientationChanged.html", { + ready: function (element, options) { + var disableOpen = true; + document.getElementById("scenario4Open").addEventListener("click", enableOrientationChangedScenario, false); + document.getElementById("scenario4Revoke").addEventListener("click", disableOrientationChangedScenario, false); + document.getElementById("scenario4Revoke").disabled = true; + + displayInformation = Windows.Graphics.Display.DisplayInformation.getForCurrentView(); + + // Get two instances of the accelerometer: + // One that returns the raw accelerometer data + accelerometerOriginal = Windows.Devices.Sensors.Accelerometer.getDefault(); + // Other on which the 'ReadingTransform' is updated so that data returned aligns with the request transformation. + accelerometerReadingTransform = Windows.Devices.Sensors.Accelerometer.getDefault(); + + if (!accelerometerOriginal || !accelerometerReadingTransform) { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } else { + disableOpen = false; + displayInformation.addEventListener("orientationchanged", onOrientationChanged); + } + document.getElementById("scenario4Open").disabled = disableOpen; + }, + unload: function () { + if (!document.getElementById("scenario4Revoke").disabled) { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + displayInformation.removeEventListener("orientationchanged", onOrientationChanged); + accelerometerOriginal.removeEventListener("readingchanged", onDataChangedOriginal); + accelerometerReadingTransform.removeEventListener("readingchanged", onDataChangedReadingTransform); + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometerOriginal.reportInterval = 0; + accelerometerReadingTransform.reportInterval = 0; + } + } + }); + + function visibilityChangeHandler() { + // This is the event handler for VisibilityChanged events. You would register for these notifications + // if handling sensor data when the app is not visible could cause unintended actions in the app. + if (!document.getElementById("scenario4Revoke").disabled) { + if (document.msVisibilityState === "visible") { + // Re-enable sensor input. No need to restore the desired reportInterval (it is restored for us upon app resume) + accelerometerOriginal.addEventListener("readingchanged", onDataChangedOriginal); + accelerometerReadingTransform.addEventListener("readingchanged", onDataChangedReadingTransform); + } else { + // Disable sensor input. No need to restore the default reportInterval (resources will be released upon app suspension) + accelerometerOriginal.removeEventListener("readingchanged", onDataChangedOriginal); + accelerometerReadingTransform.removeEventListener("readingchanged", onDataChangedReadingTransform); + } + } + } + + function onDataChangedOriginal(e) { + var reading = e.reading; + + // event can still be in queue after unload is called + // so check if elements are still loaded + + if (document.getElementById("eventOutputXOriginal")) { + document.getElementById("eventOutputXOriginal").innerHTML = reading.accelerationX.toFixed(2); + } + if (document.getElementById("eventOutputYOriginal")) { + document.getElementById("eventOutputYOriginal").innerHTML = reading.accelerationY.toFixed(2); + } + if (document.getElementById("eventOutputZOriginal")) { + document.getElementById("eventOutputZOriginal").innerHTML = reading.accelerationZ.toFixed(2); + } + } + + function onDataChangedReadingTransform(e) { + var reading = e.reading; + + // event can still be in queue after unload is called + // so check if elements are still loaded + + if (document.getElementById("eventOutputXDataTransform")) { + document.getElementById("eventOutputXDataTransform").innerHTML = reading.accelerationX.toFixed(2); + } + if (document.getElementById("eventOutputYDataTransform")) { + document.getElementById("eventOutputYDataTransform").innerHTML = reading.accelerationY.toFixed(2); + } + if (document.getElementById("eventOutputZDataTransform")) { + document.getElementById("eventOutputZDataTransform").innerHTML = reading.accelerationZ.toFixed(2); + } + } + + function enableOrientationChangedScenario() { + // Set the reportInterval to enable the sensor events + accelerometerOriginal.reportInterval = accelerometerOriginal.minimumReportInterval; + accelerometerReadingTransform.reportInterval = accelerometerReadingTransform.minimumReportInterval; + + // Set the readingTransform to align with the current display orientation + accelerometerReadingTransform.readingTransform = displayInformation.currentOrientation; + + accelerometerOriginal.addEventListener("readingchanged", onDataChangedOriginal); + accelerometerReadingTransform.addEventListener("readingchanged", onDataChangedReadingTransform); + + document.addEventListener("visibilitychange", visibilityChangeHandler, false); + + document.getElementById("scenario4Open").disabled = true; + document.getElementById("scenario4Revoke").disabled = false; + } + + function disableOrientationChangedScenario() { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometerOriginal.removeEventListener("readingchanged", onDataChangedOriginal); + accelerometerReadingTransform.removeEventListener("readingchanged", onDataChangedReadingTransform); + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometerOriginal.reportInterval = 0; + accelerometerReadingTransform.reportInterval = 0; + + document.getElementById("scenario4Open").disabled = false; + document.getElementById("scenario4Revoke").disabled = true; + } + + function onOrientationChanged(eventArgs) { + if (accelerometerReadingTransform) { + accelerometerReadingTransform.readingTransform = eventArgs.target.currentOrientation; + } + } +})(); diff --git a/Samples/Accelerometer/js/js/scenario5_DataEventsBatching.js b/Samples/Accelerometer/js/js/scenario5_DataEventsBatching.js new file mode 100644 index 0000000000..172a794d7e --- /dev/null +++ b/Samples/Accelerometer/js/js/scenario5_DataEventsBatching.js @@ -0,0 +1,98 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var reportInterval = 0; + var reportLatency = 0; + var accelerometer; + + var page = WinJS.UI.Pages.define("/html/scenario5_DataEventsBatching.html", { + ready: function (element, options) { + document.getElementById("scenario5Open").addEventListener("click", enableReadingChangedScenario, false); + document.getElementById("scenario5Revoke").addEventListener("click", disableReadingChangedScenario, false); + document.getElementById("scenario5Open").disabled = false; + document.getElementById("scenario5Revoke").disabled = true; + + accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault(); + if (accelerometer) { + // Select a report interval that is both suitable for the purposes of the app and supported by the sensor. + // This value will be used later to activate the sensor. + var minimumReportInterval = accelerometer.minimumReportInterval; + reportInterval = minimumReportInterval > 16 ? minimumReportInterval : 16; + + // MaxBatchSize will be 0 if the accelerometer does not support batching. + var maxLatency = accelerometer.MaxBatchSize * reportLatency; + reportLatency = maxLatency < 10 ? maxLatency : 10; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + }, + unload: function () { + if (document.getElementById("scenario5Open").disabled) { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.removeEventListener("readingchanged", onDataChanged); + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometer.reportInterval = 0; + } + } + }); + + function visibilityChangeHandler() { + // This is the event handler for VisibilityChanged events. You would register for these notifications + // if handling sensor data when the app is not visible could cause unintended actions in the app. + if (document.getElementById("scenario5Open").disabled) { + if (document.msVisibilityState === "visible") { + // Re-enable sensor input. No need to restore the desired reportInterval (it is restored for us upon app resume) + accelerometer.addEventListener("readingchanged", onDataChanged); + } else { + // Disable sensor input. No need to restore the default reportInterval (resources will be released upon app suspension) + accelerometer.removeEventListener("readingchanged", onDataChanged); + } + } + } + + function onDataChanged(e) { + var reading = e.reading; + + // event can still be in queue after unload is called + // so check if elements are still loaded + + if (document.getElementById("eventOutputX")) { + document.getElementById("eventOutputX").innerHTML = reading.accelerationX.toFixed(2); + } + if (document.getElementById("eventOutputY")) { + document.getElementById("eventOutputY").innerHTML = reading.accelerationY.toFixed(2); + } + if (document.getElementById("eventOutputZ")) { + document.getElementById("eventOutputZ").innerHTML = reading.accelerationZ.toFixed(2); + } + } + + function enableReadingChangedScenario() { + if (accelerometer) { + // Set the reportInterval to enable the sensor events + accelerometer.reportInterval = reportInterval; + + // Set the report latency. This is a no-op if the accelerometer does not support batching + accelerometer.reportLatency = reportLatency; + + document.addEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.addEventListener("readingchanged", onDataChanged); + document.getElementById("scenario5Open").disabled = true; + document.getElementById("scenario5Revoke").disabled = false; + } else { + WinJS.log && WinJS.log("No accelerometer found", "sample", "error"); + } + } + + function disableReadingChangedScenario() { + document.removeEventListener("visibilitychange", visibilityChangeHandler, false); + accelerometer.removeEventListener("readingchanged", onDataChanged); + document.getElementById("scenario5Open").disabled = false; + document.getElementById("scenario5Revoke").disabled = true; + + // Return the report interval to its default to release resources while the sensor is not in use + accelerometer.reportInterval = 0; + } +})(); diff --git a/Samples/Accelerometer/js/sample-utils/placeholder.txt b/Samples/Accelerometer/js/sample-utils/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/README.md b/Samples/AccountPictureName/README.md new file mode 100644 index 0000000000..789d459ba8 --- /dev/null +++ b/Samples/AccountPictureName/README.md @@ -0,0 +1,53 @@ + +# Account picture name sample + +This sample demonstrates different ways of getting the name of the user that is currently logged in. It also demonstrates how to get and set the image used for the user's tile. + +Specifically, this sample demonstrates the following scenarios: + +- How to get the [**DisplayName**](http://msdn.microsoft.com/library/windows/apps/hh921595) for the current logged on user. +- How to get the first and last name for the current logged on user. (This is available only for Microsoft accounts. An empty string is returned if a Microsoft account is not available.) +- How to obtain the logged on user's account picture as a bitmap. You can get request three different types: small, large, and video. If the size that is requested is not available an empty file is returned. +- How to set the account picture for the currently logged on user. You can set three different types: small, large, and video. (More than one type can be set in the same call, but a small image must be accompanied by a large image and/or video.) +- How to register for a change event for account picture updates. + +**Note** The Universal Windows app samples require Visual Studio 2015 to build and Windows 10 to execute. + +To obtain information about Windows 10, go to [Windows 10](http://go.microsoft.com/fwlink/?LinkID=532421) + +To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422) + +## Related topics + +### Reference + +[**Windows.System.UserProfile** namespace](http://msdn.microsoft.com/library/windows/apps/br241881) + +## System requirements + +**Client:** Windows 10 + +**Server:** Windows Server 2016 Technical Preview + +**Phone:** Not supported + +## Build the sample + +1. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**. +2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the language you desire - either C++, C#, or JavaScript. Double-click the Visual Studio 2015 Solution (.sln) file. +3. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**. + +## Run the sample + +The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it. + +### Deploying the sample + +- Select Build > Deploy Solution. + +### Deploying and running the sample + +- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or select Debug > Start Without Debugging. + diff --git a/Samples/AccountPictureName/cpp/AccountPictureName.sln b/Samples/AccountPictureName/cpp/AccountPictureName.sln new file mode 100644 index 0000000000..80b5afae19 --- /dev/null +++ b/Samples/AccountPictureName/cpp/AccountPictureName.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AccountPictureName", "AccountPictureName.vcxproj", "{C5B886A7-8300-46FF-B533-9613DE2AF637}" +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 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.ActiveCfg = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.Build.0 = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.Deploy.0 = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.ActiveCfg = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.Build.0 = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.Deploy.0 = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x86.ActiveCfg = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x86.Build.0 = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x86.Deploy.0 = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.ActiveCfg = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.Build.0 = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.Deploy.0 = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.ActiveCfg = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.Build.0 = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.Deploy.0 = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x86.ActiveCfg = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x86.Build.0 = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/AccountPictureName/cpp/AccountPictureName.vcxproj b/Samples/AccountPictureName/cpp/AccountPictureName.vcxproj new file mode 100644 index 0000000000..176706c626 --- /dev/null +++ b/Samples/AccountPictureName/cpp/AccountPictureName.vcxproj @@ -0,0 +1,245 @@ + + + + {C5B886A7-8300-46FF-B533-9613DE2AF637} + SDKTemplate + en-US + 14.0 + true + Windows Store + 10.0 + 10.0.10240.0 + 10.0.10240.0 + true + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + Application + true + v140 + + + Application + true + v140 + + + Application + true + v140 + + + Application + false + true + v140 + true + + + Application + false + true + v140 + true + + + Application + false + true + v140 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\..\SharedContent\cpp + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + + ..\..\..\SharedContent\xaml\App.xaml + + + ..\..\..\SharedContent\cpp\MainPage.xaml + + + + ..\shared\GetAccountPicture.xaml + + + ..\shared\GetUserDisplayName.xaml + + + ..\shared\GetUserFirstAndLastName.xaml + + + ..\shared\SetAccountPicture.xaml + + + + + Designer + + + Designer + + + + + + + Styles\Styles.xaml + + + + + Designer + + + + + ..\..\..\SharedContent\xaml\App.xaml + + + ..\..\..\SharedContent\cpp\MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + ..\shared\GetAccountPicture.xaml + + + ..\shared\GetUserDisplayName.xaml + + + ..\shared\GetUserFirstAndLastName.xaml + + + ..\shared\SetAccountPicture.xaml + + + + + 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 + + + + + + + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/cpp/AccountPictureName.vcxproj.filters b/Samples/AccountPictureName/cpp/AccountPictureName.vcxproj.filters new file mode 100644 index 0000000000..21f9938e98 --- /dev/null +++ b/Samples/AccountPictureName/cpp/AccountPictureName.vcxproj.filters @@ -0,0 +1,71 @@ + + + + + 80bfd669-aa83-4537-9611-027cffe0d8af + bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png + + + {c6978fb6-bc64-498d-97c8-f5b53997e54e} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Styles + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/cpp/GetAccountPicture.xaml.cpp b/Samples/AccountPictureName/cpp/GetAccountPicture.xaml.cpp new file mode 100644 index 0000000000..6570deefcc --- /dev/null +++ b/Samples/AccountPictureName/cpp/GetAccountPicture.xaml.cpp @@ -0,0 +1,155 @@ +//********************************************************* +// +// 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 "GetAccountPicture.xaml.h" + +using namespace SDKTemplate; + +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Storage; +using namespace Windows::Storage::Streams; +using namespace Windows::System::UserProfile; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Media::Imaging; +using namespace Windows::UI::Xaml::Navigation; + +GetAccountPicture::GetAccountPicture() : rootPage(MainPage::Current) +{ + InitializeComponent(); +} + +void GetAccountPicture::GetSmallImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + HideImageAndVideoControls(); + + if (UserInformation::NameAccessAllowed) + { + auto smallImageFile = UserInformation::GetAccountPicture(AccountPictureKind::SmallImage); + if (smallImageFile != nullptr) + { + rootPage->NotifyUser("Path = " + smallImageFile->Path, NotifyType::StatusMessage); + create_task(smallImageFile->OpenReadAsync()).then( + [this](task imageStreamTask) + { + try + { + auto imageStream = imageStreamTask.get(); + auto bitmapImage = ref new BitmapImage(); + bitmapImage->SetSource(imageStream); + SmallImage->Source = bitmapImage; + SmallImage->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + catch (Exception^ ex) + { + rootPage->NotifyUser("Error opening stream: " + ex->Message, NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("Small account picture is not available.", NotifyType::ErrorMessage); + } + } + else + { + rootPage->NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } +} + +void GetAccountPicture::GetLargeImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + HideImageAndVideoControls(); + + if (UserInformation::NameAccessAllowed) + { + auto largeImageFile = UserInformation::GetAccountPicture(AccountPictureKind::LargeImage); + if (largeImageFile != nullptr) + { + rootPage->NotifyUser("Path = " + largeImageFile->Path, NotifyType::StatusMessage); + create_task(largeImageFile->OpenReadAsync()).then( + [this](task imageStreamTask) + { + try + { + auto imageStream = imageStreamTask.get(); + auto bitmapImage = ref new BitmapImage(); + bitmapImage->SetSource(imageStream); + LargeImage->Source = bitmapImage; + LargeImage->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + catch (Exception^ ex) + { + rootPage->NotifyUser("Error opening stream: " + ex->Message, NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("No large account picture image returned for current user.", NotifyType::ErrorMessage); + } + } + else + { + rootPage->NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } +} + +void GetAccountPicture::GetVideoButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + HideImageAndVideoControls(); + + if (UserInformation::NameAccessAllowed) + { + auto videoFile = UserInformation::GetAccountPicture(AccountPictureKind::Video); + if (videoFile != nullptr) + { + rootPage->NotifyUser("Path = " + videoFile->Path, NotifyType::StatusMessage); + create_task(videoFile->OpenReadAsync()).then( + [this](task videoStreamTask) + { + try + { + auto videoStream = videoStreamTask.get(); + MediaPlayer->SetSource(videoStream, "video/mp4"); + MediaPlayer->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + catch (Exception^ ex) + { + rootPage->NotifyUser("Error opening stream: " + ex->Message, NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("Video is not available.", NotifyType::ErrorMessage); + } + } + else + { + rootPage->NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } +} + +void GetAccountPicture::HideImageAndVideoControls() +{ + SmallImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + LargeImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + MediaPlayer->Visibility = Windows::UI::Xaml::Visibility::Collapsed; +} diff --git a/Samples/AccountPictureName/cpp/GetAccountPicture.xaml.h b/Samples/AccountPictureName/cpp/GetAccountPicture.xaml.h new file mode 100644 index 0000000000..0d6ad31bd4 --- /dev/null +++ b/Samples/AccountPictureName/cpp/GetAccountPicture.xaml.h @@ -0,0 +1,31 @@ +//********************************************************* +// +// 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 "GetAccountPicture.g.h" +#include "MainPage.xaml.h" + +namespace SDKTemplate +{ + [Windows::Foundation::Metadata::WebHostHidden] + public ref class GetAccountPicture sealed + { + public: + GetAccountPicture(); + private: + MainPage^ rootPage; + void GetSmallImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void GetLargeImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void GetVideoButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void HideImageAndVideoControls(); + }; +} diff --git a/Samples/AccountPictureName/cpp/GetUserDisplayName.xaml.cpp b/Samples/AccountPictureName/cpp/GetUserDisplayName.xaml.cpp new file mode 100644 index 0000000000..ecc0c71d6c --- /dev/null +++ b/Samples/AccountPictureName/cpp/GetUserDisplayName.xaml.cpp @@ -0,0 +1,55 @@ +//********************************************************* +// +// 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 "GetUserDisplayName.xaml.h" + +using namespace SDKTemplate; + +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::System::UserProfile; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +GetUserDisplayName::GetUserDisplayName() : rootPage(SDKTemplate::MainPage::Current) +{ + InitializeComponent(); +} + +void GetUserDisplayName::GetDisplayNameButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + if (UserInformation::NameAccessAllowed) + { + create_task(UserInformation::GetDisplayNameAsync()).then([this](String^ displayName) + { + if (displayName != nullptr) + { + rootPage->NotifyUser("Display name = " + displayName, NotifyType::StatusMessage); + } + else + { + rootPage->NotifyUser("No display name was returned.", NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("Access to name disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } +} diff --git a/Samples/AccountPictureName/cpp/GetUserDisplayName.xaml.h b/Samples/AccountPictureName/cpp/GetUserDisplayName.xaml.h new file mode 100644 index 0000000000..2830f0c074 --- /dev/null +++ b/Samples/AccountPictureName/cpp/GetUserDisplayName.xaml.h @@ -0,0 +1,29 @@ +//********************************************************* +// +// 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 "GetUserDisplayName.g.h" +#include "MainPage.xaml.h" + +namespace SDKTemplate +{ + [Windows::Foundation::Metadata::WebHostHidden] + public ref class GetUserDisplayName sealed + { + public: + GetUserDisplayName(); + + private: + MainPage^ rootPage; + void GetDisplayNameButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + }; +} diff --git a/Samples/AccountPictureName/cpp/GetUserFirstAndLastName.xaml.cpp b/Samples/AccountPictureName/cpp/GetUserFirstAndLastName.xaml.cpp new file mode 100644 index 0000000000..d1fa5cda87 --- /dev/null +++ b/Samples/AccountPictureName/cpp/GetUserFirstAndLastName.xaml.cpp @@ -0,0 +1,77 @@ +//********************************************************* +// +// 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 "GetUserFirstAndLastName.xaml.h" + +using namespace SDKTemplate; + +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::System::UserProfile; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +GetUserFirstAndLastName::GetUserFirstAndLastName() : rootPage(MainPage::Current) +{ + InitializeComponent(); +} + +void GetUserFirstAndLastName::GetFirstNameButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + if (UserInformation::NameAccessAllowed) + { + create_task(UserInformation::GetFirstNameAsync()).then([this](String^ firstName) + { + if (firstName != nullptr) + { + rootPage->NotifyUser("First name = " + firstName, NotifyType::StatusMessage); + } + else + { + rootPage->NotifyUser("No first name was returned.", NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("Access to name disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } +} + +void GetUserFirstAndLastName::GetLastNameButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + if (UserInformation::NameAccessAllowed) + { + create_task(UserInformation::GetLastNameAsync()).then([this](String^ lastName) + { + if (lastName != nullptr) + { + rootPage->NotifyUser("Last name = " + lastName, NotifyType::StatusMessage); + } + else + { + rootPage->NotifyUser("No last name was returned.", NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("Access to name disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } +} diff --git a/Samples/AccountPictureName/cpp/GetUserFirstAndLastName.xaml.h b/Samples/AccountPictureName/cpp/GetUserFirstAndLastName.xaml.h new file mode 100644 index 0000000000..c337a2bb0f --- /dev/null +++ b/Samples/AccountPictureName/cpp/GetUserFirstAndLastName.xaml.h @@ -0,0 +1,29 @@ +//********************************************************* +// +// 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 "GetUserFirstAndLastName.g.h" +#include "MainPage.xaml.h" + +namespace SDKTemplate +{ + [Windows::Foundation::Metadata::WebHostHidden] + public ref class GetUserFirstAndLastName sealed + { + public: + GetUserFirstAndLastName(); + private: + MainPage^ rootPage; + void GetFirstNameButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void GetLastNameButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + }; +} diff --git a/Samples/AccountPictureName/cpp/Package.appxmanifest b/Samples/AccountPictureName/cpp/Package.appxmanifest new file mode 100644 index 0000000000..eab571cc5d --- /dev/null +++ b/Samples/AccountPictureName/cpp/Package.appxmanifest @@ -0,0 +1,56 @@ + + + + + + + + + + Account Picture Name C++ Sample + Microsoft Corporation + Assets\StoreLogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/cpp/SampleConfiguration.cpp b/Samples/AccountPictureName/cpp/SampleConfiguration.cpp new file mode 100644 index 0000000000..a28a93699c --- /dev/null +++ b/Samples/AccountPictureName/cpp/SampleConfiguration.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft. All rights reserved. + +#include "pch.h" +#include "MainPage.xaml.h" +#include "SampleConfiguration.h" + +using namespace SDKTemplate; +using namespace Platform; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +Platform::Array^ MainPage::scenariosInner = ref new Platform::Array +{ + { "Get display name", "SDKTemplate.GetUserDisplayName" }, + { "Get first and last name", "SDKTemplate.GetUserFirstAndLastName" }, + { "Get account picture", "SDKTemplate.GetAccountPicture" }, + { "Set account picture and listen for changes", "SDKTemplate.SetAccountPicture" } +}; + +void App::OnActivated(IActivatedEventArgs^ args) +{ + // Check to see if the app was activated via a protocol + if (args->Kind == ActivationKind::Protocol) + { + auto protocolArgs = safe_cast(args); + if (protocolArgs->Uri->SchemeName->Equals("ms-accountpictureprovider")) + { + if (Window::Current->Content == nullptr) + { + auto rootFrame = ref new Frame(); + TypeName pageType = { "SDKTemplate.MainPage", TypeKind::Custom }; + rootFrame->Navigate(pageType); + Window::Current->Content = rootFrame; + Window::Current->Activate(); + } + + MainPage::Current->NavigateToScenario("SDKTemplate.SetAccountPicture"); + } + } +} diff --git a/Samples/AccountPictureName/cpp/SampleConfiguration.h b/Samples/AccountPictureName/cpp/SampleConfiguration.h new file mode 100644 index 0000000000..9a7651fd7b --- /dev/null +++ b/Samples/AccountPictureName/cpp/SampleConfiguration.h @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. + +#pragma once +#include "pch.h" + +namespace SDKTemplate +{ + value struct Scenario; + + partial ref class MainPage + { + internal: + static property Platform::String^ FEATURE_NAME + { + Platform::String^ get() + { + return "Account picture name C++ sample"; + } + } + + static property Platform::Array^ scenarios + { + Platform::Array^ get() + { + return scenariosInner; + } + } + + void NavigateToScenario(Platform::String^ scenario) + { + for (unsigned index = 0; index < scenarios->Length; index++) + { + if (scenarios[index].ClassName == scenario) + { + ScenarioControl->SelectedIndex = index; + break; + } + } + } + + private: + static Platform::Array^ scenariosInner; + }; + + public value struct Scenario + { + Platform::String^ Title; + Platform::String^ ClassName; + }; + + partial ref class App sealed + { + protected: + virtual void OnActivated(Windows::ApplicationModel::Activation::IActivatedEventArgs^ args) override; + }; +} diff --git a/Samples/AccountPictureName/cpp/SetAccountPicture.xaml.cpp b/Samples/AccountPictureName/cpp/SetAccountPicture.xaml.cpp new file mode 100644 index 0000000000..4b565f9ff7 --- /dev/null +++ b/Samples/AccountPictureName/cpp/SetAccountPicture.xaml.cpp @@ -0,0 +1,160 @@ +//********************************************************* +// +// 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 "SetAccountPicture.xaml.h" + +using namespace SDKTemplate; + +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Storage; +using namespace Windows::Storage::Streams; +using namespace Windows::Storage::Pickers; +using namespace Windows::System::UserProfile; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Media::Imaging; +using namespace Windows::UI::Xaml::Navigation; + +SetAccountPicture::SetAccountPicture() : rootPage(MainPage::Current) +{ + InitializeComponent(); +} + +void SetAccountPicture::OnNavigatedTo(NavigationEventArgs^ e) +{ + accountPictureChangedToken = UserInformation::AccountPictureChanged += ref new EventHandler(this, &SetAccountPicture::PictureChanged); +} + +void SetAccountPicture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + UserInformation::AccountPictureChanged -= accountPictureChangedToken; +} + +void SetAccountPicture::SetImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + FileOpenPicker^ imagePicker = ref new FileOpenPicker(); + imagePicker->ViewMode = PickerViewMode::Thumbnail; + imagePicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary; + imagePicker->FileTypeFilter->Append(".jpg"); + imagePicker->FileTypeFilter->Append(".jpeg"); + imagePicker->FileTypeFilter->Append(".png"); + imagePicker->FileTypeFilter->Append(".bmp"); + + create_task(imagePicker->PickSingleFileAsync()).then( + [this](StorageFile^ imageFile) + { + if (imageFile != nullptr) + { + rootPage->NotifyUser("Setting " + imageFile->Name + " as account picture ...", + NotifyType::StatusMessage); + create_task(UserInformation::SetAccountPictureAsync(imageFile)).then( + [this](SetAccountPictureResult setPictureResult) + { + if (setPictureResult == SetAccountPictureResult::Success) + { + rootPage->NotifyUser("Successfully updated account picture.", NotifyType::StatusMessage); + } + else + { + rootPage->NotifyUser("Setting account picture failed.", NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("No image was selected.", NotifyType::StatusMessage); + } + }); +} + +void SetAccountPicture::SetVideoButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + FileOpenPicker^ videoPicker = ref new FileOpenPicker(); + videoPicker->ViewMode = PickerViewMode::Thumbnail; + videoPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary; + videoPicker->FileTypeFilter->Append(".mp4"); + videoPicker->FileTypeFilter->Append(".wmv"); + videoPicker->FileTypeFilter->Append(".mpeg"); + videoPicker->FileTypeFilter->Append(".mov"); + + create_task(videoPicker->PickSingleFileAsync()).then( + [this](StorageFile^ videoFile) + { + if (videoFile != nullptr) + { + rootPage->NotifyUser("Setting " + videoFile->Name + " as account picture ...", + NotifyType::StatusMessage); + create_task(UserInformation::SetAccountPictureAsync(videoFile)).then( + [this](SetAccountPictureResult setPictureResult) + { + if (setPictureResult == SetAccountPictureResult::Success) + { + rootPage->NotifyUser("Successfully updated account picture.", NotifyType::StatusMessage); + } + else + { + rootPage->NotifyUser("Setting account picture failed.", NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("No video was selected.", NotifyType::StatusMessage); + } + }); +} + +void SetAccountPicture::PictureChanged(Platform::Object^ sender, Platform::Object^ e) +{ + Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]() + { + if (UserInformation::NameAccessAllowed) + { + auto largeImageFile = UserInformation::GetAccountPicture(AccountPictureKind::LargeImage); + if (largeImageFile != nullptr) + { + create_task(largeImageFile->OpenReadAsync()).then( + [this](task imageStreamTask) + { + try + { + auto imageStream = imageStreamTask.get(); + auto bitmapImage = ref new BitmapImage(); + bitmapImage->SetSource(imageStream); + AccountPictureImage->Source = bitmapImage; + AccountPictureImage->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + catch (Exception^ ex) + { + rootPage->NotifyUser("Failed to read from stream. " + ex->Message, NotifyType::ErrorMessage); + } + }); + } + else + { + rootPage->NotifyUser("No large account picture image returned for current user.", NotifyType::ErrorMessage); + } + } + else + { + rootPage->NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType::ErrorMessage); + } + })); +} diff --git a/Samples/AccountPictureName/cpp/SetAccountPicture.xaml.h b/Samples/AccountPictureName/cpp/SetAccountPicture.xaml.h new file mode 100644 index 0000000000..e5cf9fdb9a --- /dev/null +++ b/Samples/AccountPictureName/cpp/SetAccountPicture.xaml.h @@ -0,0 +1,36 @@ +//********************************************************* +// +// 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 "SetAccountPicture.g.h" +#include "MainPage.xaml.h" + +namespace SDKTemplate +{ + [Windows::Foundation::Metadata::WebHostHidden] + public ref class SetAccountPicture sealed + { + public: + SetAccountPicture(); + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + + private: + MainPage^ rootPage; + void SetImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void SetVideoButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void PictureChanged(Platform::Object^ sender, Platform::Object^ e); + + Windows::Foundation::EventRegistrationToken accountPictureChangedToken; + }; +} diff --git a/Samples/AccountPictureName/cpp/pch.cpp b/Samples/AccountPictureName/cpp/pch.cpp new file mode 100644 index 0000000000..ade821753a --- /dev/null +++ b/Samples/AccountPictureName/cpp/pch.cpp @@ -0,0 +1,5 @@ +// +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/Samples/AccountPictureName/cpp/pch.h b/Samples/AccountPictureName/cpp/pch.h new file mode 100644 index 0000000000..2662955e22 --- /dev/null +++ b/Samples/AccountPictureName/cpp/pch.h @@ -0,0 +1,11 @@ +// +// Header for standard system include files. +// + +#pragma once + +#include +#include + +#include "SampleConfiguration.h" +#include "App.xaml.h" diff --git a/Samples/AccountPictureName/cs/AccountPictureName.csproj b/Samples/AccountPictureName/cs/AccountPictureName.csproj new file mode 100644 index 0000000000..c0acb7551d --- /dev/null +++ b/Samples/AccountPictureName/cs/AccountPictureName.csproj @@ -0,0 +1,203 @@ + + + + + Debug + x86 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4} + AppContainerExe + Properties + SDKTemplate + AccountPictureName + en-US + UAP + 10.0.10240.0 + 10.0.10240.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + App.xaml.cs + App.xaml + + + MainPage.xaml.cs + MainPage.xaml + + + Properties\AssemblyInfo.cs + + + + GetUserDisplayName.xaml + + + GetAccountPicture.xaml + + + GetUserFirstAndLastName.xaml + + + SetAccountPicture.xaml + + + + + Designer + + + + + App.xaml + MSBuild:Compile + Designer + + + MainPage.xaml + MSBuild:Compile + Designer + + + GetUserDisplayName.xaml + MSBuild:Compile + Designer + + + GetAccountPicture.xaml + MSBuild:Compile + Designer + + + GetUserFirstAndLastName.xaml + MSBuild:Compile + Designer + + + SetAccountPicture.xaml + MSBuild:Compile + Designer + + + Styles\Styles.xaml + MSBuild:Compile + Designer + + + + + Properties\Default.rd.xml + + + 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 + + + + + Microsoft Desktop Extension SDK for Universal App Platform + + + + 14.0 + + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/cs/AccountPictureName.sln b/Samples/AccountPictureName/cs/AccountPictureName.sln new file mode 100644 index 0000000000..8924a9375e --- /dev/null +++ b/Samples/AccountPictureName/cs/AccountPictureName.sln @@ -0,0 +1,43 @@ + + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22609.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AccountPictureName", "AccountPictureName.csproj", "{CF1CD0D5-BF6B-457A-9927-8079FC667CA4}" +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 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|ARM.ActiveCfg = Debug|ARM + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|ARM.Build.0 = Debug|ARM + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|ARM.Deploy.0 = Debug|ARM + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|x64.ActiveCfg = Debug|x64 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|x64.Build.0 = Debug|x64 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|x64.Deploy.0 = Debug|x64 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|x86.ActiveCfg = Debug|x86 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|x86.Build.0 = Debug|x86 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Debug|x86.Deploy.0 = Debug|x86 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|ARM.ActiveCfg = Release|ARM + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|ARM.Build.0 = Release|ARM + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|ARM.Deploy.0 = Release|ARM + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|x64.ActiveCfg = Release|x64 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|x64.Build.0 = Release|x64 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|x64.Deploy.0 = Release|x64 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|x86.ActiveCfg = Release|x86 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|x86.Build.0 = Release|x86 + {CF1CD0D5-BF6B-457A-9927-8079FC667CA4}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal + + diff --git a/Samples/AccountPictureName/cs/GetAccountPicture.xaml.cs b/Samples/AccountPictureName/cs/GetAccountPicture.xaml.cs new file mode 100644 index 0000000000..53a4af871a --- /dev/null +++ b/Samples/AccountPictureName/cs/GetAccountPicture.xaml.cs @@ -0,0 +1,151 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using System; +using Windows.Storage; +using Windows.Storage.Streams; +using Windows.UI.Xaml.Media.Imaging; +using Windows.System.UserProfile; + +namespace SDKTemplate +{ + public sealed partial class GetAccountPicture : Page + { + private MainPage rootPage; + + public GetAccountPicture() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + private async void GetSmallImageButton_Click(object sender, RoutedEventArgs e) + { + HideImageAndVideoControls(); + + if (UserInformation.NameAccessAllowed) + { + // The small picture returned by GetAccountPicture() is 96x96 pixels in size. + StorageFile image = UserInformation.GetAccountPicture(AccountPictureKind.SmallImage) as StorageFile; + if (image != null) + { + rootPage.NotifyUser("Path = " + image.Path, NotifyType.StatusMessage); + + try + { + IRandomAccessStream imageStream = await image.OpenReadAsync(); + BitmapImage bitmapImage = new BitmapImage(); + bitmapImage.SetSource(imageStream); + SmallImage.Source = bitmapImage; + SmallImage.Visibility = Visibility.Visible; + } + catch (Exception ex) + { + rootPage.NotifyUser("Error opening stream: " + ex.ToString(), NotifyType.ErrorMessage); + } + } + else + { + rootPage.NotifyUser("Small account picture is not available.", NotifyType.StatusMessage); + } + } + else + { + rootPage.NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType.ErrorMessage); + } + } + + private async void GetLargeImageButton_Click(object sender, RoutedEventArgs e) + { + HideImageAndVideoControls(); + + if (UserInformation.NameAccessAllowed) + { + // The large picture returned by GetAccountPicture() is 448x448 pixels in size. + StorageFile image = UserInformation.GetAccountPicture(AccountPictureKind.LargeImage) as StorageFile; + if (image != null) + { + rootPage.NotifyUser("Path = " + image.Path, NotifyType.StatusMessage); + + try + { + IRandomAccessStream imageStream = await image.OpenReadAsync(); + BitmapImage bitmapImage = new BitmapImage(); + bitmapImage.SetSource(imageStream); + LargeImage.Source = bitmapImage; + LargeImage.Visibility = Visibility.Visible; + } + catch (Exception ex) + { + rootPage.NotifyUser("Error opening stream: " + ex.ToString(), NotifyType.ErrorMessage); + } + } + else + { + rootPage.NotifyUser("Large account picture is not available.", NotifyType.StatusMessage); + } + } + else + { + rootPage.NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType.ErrorMessage); + } + } + + private async void GetVideoButton_Click(object sender, RoutedEventArgs e) + { + HideImageAndVideoControls(); + + if (UserInformation.NameAccessAllowed) + { + // The video returned from getAccountPicture is 448x448 pixels in size. + StorageFile video = UserInformation.GetAccountPicture(AccountPictureKind.Video) as StorageFile; + if (video != null) + { + rootPage.NotifyUser("Path: " + video.Path, NotifyType.StatusMessage); + + try + { + IRandomAccessStream videoStream = await video.OpenAsync(FileAccessMode.Read); + MediaPlayer.SetSource(videoStream, "video/mp4"); + MediaPlayer.Visibility = Visibility.Visible; + } + catch (Exception ex) + { + rootPage.NotifyUser("Error opening stream: " + ex.ToString(), NotifyType.ErrorMessage); + } + } + else + { + rootPage.NotifyUser("Video is not available.", NotifyType.StatusMessage); + } + } + else + { + rootPage.NotifyUser("Access to account picture disabled by Privacy Setting or Group Policy.", NotifyType.ErrorMessage); + } + } + + private void HideImageAndVideoControls() + { + SmallImage.Visibility = Visibility.Collapsed; + LargeImage.Visibility = Visibility.Collapsed; + MediaPlayer.Visibility = Visibility.Collapsed; + } + + } +} diff --git a/Samples/AccountPictureName/cs/GetUserDisplayName.xaml.cs b/Samples/AccountPictureName/cs/GetUserDisplayName.xaml.cs new file mode 100644 index 0000000000..9288f48a59 --- /dev/null +++ b/Samples/AccountPictureName/cs/GetUserDisplayName.xaml.cs @@ -0,0 +1,54 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using System; +using Windows.System.UserProfile; + +namespace SDKTemplate +{ + public sealed partial class GetUserDisplayName : Page + { + private MainPage rootPage; + + public GetUserDisplayName() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + private async void GetDisplayNameButton_Click(object sender, RoutedEventArgs e) + { + if (UserInformation.NameAccessAllowed) + { + string displayName = await UserInformation.GetDisplayNameAsync(); + if (string.IsNullOrEmpty(displayName)) + { + rootPage.NotifyUser("No display name was returned.", NotifyType.StatusMessage); + } + else + { + rootPage.NotifyUser("Display name = " + displayName, NotifyType.StatusMessage); + } + } + else + { + rootPage.NotifyUser("Access to name disabled by Privacy Setting or Group Policy.", NotifyType.ErrorMessage); + } + } + } +} diff --git a/Samples/AccountPictureName/cs/GetUserFirstAndLastName.xaml.cs b/Samples/AccountPictureName/cs/GetUserFirstAndLastName.xaml.cs new file mode 100644 index 0000000000..ba1643b7b7 --- /dev/null +++ b/Samples/AccountPictureName/cs/GetUserFirstAndLastName.xaml.cs @@ -0,0 +1,74 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using System; +using Windows.System.UserProfile; + +namespace SDKTemplate +{ + public sealed partial class GetUserFirstAndLastName : Page + { + private MainPage rootPage; + + public GetUserFirstAndLastName() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + private async void GetFirstNameButton_Click(object sender, RoutedEventArgs e) + { + if (UserInformation.NameAccessAllowed) + { + string firstName = await UserInformation.GetFirstNameAsync(); + if (string.IsNullOrEmpty(firstName)) + { + rootPage.NotifyUser("No first name was returned.", NotifyType.StatusMessage); + } + else + { + rootPage.NotifyUser("First name = " + firstName, NotifyType.StatusMessage); + } + } + else + { + rootPage.NotifyUser("Access to name disabled by Privacy Setting or Group Policy.", NotifyType.ErrorMessage); + } + } + + private async void GetLastNameButton_Click(object sender, RoutedEventArgs e) + { + if (UserInformation.NameAccessAllowed) + { + string lastName = await UserInformation.GetLastNameAsync(); + if (string.IsNullOrEmpty(lastName)) + { + rootPage.NotifyUser("No last name was returned.", NotifyType.StatusMessage); + } + else + { + rootPage.NotifyUser("Last name = " + lastName, NotifyType.StatusMessage); + } + } + else + { + rootPage.NotifyUser("Access to name disabled by Privacy Setting or Group Policy.", NotifyType.ErrorMessage); + } + } + } +} diff --git a/Samples/AccountPictureName/cs/Package.appxmanifest b/Samples/AccountPictureName/cs/Package.appxmanifest new file mode 100644 index 0000000000..e1b4540aec --- /dev/null +++ b/Samples/AccountPictureName/cs/Package.appxmanifest @@ -0,0 +1,57 @@ + + + + + + + + + + + Account Picture Name C# Sample + Microsoft Corporation + Assets\StoreLogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/cs/SampleConfiguration.cs b/Samples/AccountPictureName/cs/SampleConfiguration.cs new file mode 100644 index 0000000000..acbb82e6ef --- /dev/null +++ b/Samples/AccountPictureName/cs/SampleConfiguration.cs @@ -0,0 +1,82 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace SDKTemplate +{ + public partial class MainPage : Page + { + public const string FEATURE_NAME = "Account picture name C# sample"; + + List scenarios = new List + { + new Scenario() { Title = "Get display name", ClassType = typeof(GetUserDisplayName) }, + new Scenario() { Title = "Get first and last name", ClassType = typeof(GetUserFirstAndLastName) }, + new Scenario() { Title = "Get account picture", ClassType = typeof(GetAccountPicture) }, + new Scenario() { Title = "Set account picture and listen for changes", ClassType = typeof(SetAccountPicture) } + }; + + public void NavigateToScenario(Type type) + { + for (int index = 0; index < scenarios.Count; index++) + { + if (scenarios[index].ClassType == type) + { + ScenarioControl.SelectedIndex = index; + break; + } + } + } + } + + public class Scenario + { + public string Title { get; set; } + public Type ClassType { get; set; } + } + + /// + /// Provides sample-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + protected override void OnActivated(IActivatedEventArgs args) + { + // Check to see if the app was activated via a protocol + if (args.Kind == ActivationKind.Protocol) + { + var protocolArgs = (ProtocolActivatedEventArgs)args; + + // This app was activated via the Account picture apps section in PC Settings / Personalize / Account picture. + // Here you would do app-specific logic so that the user receives account picture selection UX. + if (protocolArgs.Uri.Scheme == "ms-accountpictureprovider") + { + // The Content might be null if App has not yet been activated, if so first activate the main page. + if (Window.Current.Content == null) + { + Frame rootFrame = new Frame(); + rootFrame.Navigate(typeof(MainPage)); + Window.Current.Content = rootFrame; + Window.Current.Activate(); + } + MainPage.Current.NavigateToScenario(typeof(SDKTemplate.SetAccountPicture)); + } + } + } + } +} diff --git a/Samples/AccountPictureName/cs/SetAccountPicture.xaml.cs b/Samples/AccountPictureName/cs/SetAccountPicture.xaml.cs new file mode 100644 index 0000000000..a6cfa5be6f --- /dev/null +++ b/Samples/AccountPictureName/cs/SetAccountPicture.xaml.cs @@ -0,0 +1,158 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using System; + +using System.Linq; +using System.Collections.Generic; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.Graphics.Display; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Core; +using Windows.Storage.Pickers; +using Windows.Storage; +using Windows.Storage.Streams; +using Windows.UI.Xaml.Media.Imaging; +using Windows.System.UserProfile; + + +namespace SDKTemplate +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class SetAccountPicture : Page + { + MainPage rootPage = MainPage.Current; + + public SetAccountPicture() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + + //Listen to AccountPictureChanged event + UserInformation.AccountPictureChanged += this.PictureChanged; + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + //Remove listener to AccountPictureChanged event + UserInformation.AccountPictureChanged -= this.PictureChanged; + } + + private async void SetImageButton_Click(object sender, RoutedEventArgs e) + { + + FileOpenPicker imagePicker = new FileOpenPicker + { + ViewMode = PickerViewMode.Thumbnail, + SuggestedStartLocation = PickerLocationId.PicturesLibrary, + FileTypeFilter = { ".jpg", ".jpeg", ".png", ".bmp" } + }; + + StorageFile imageFile = await imagePicker.PickSingleFileAsync(); + if (imageFile != null) + { + // SetAccountPictureAsync() accepts 3 storageFile objects for setting the small image, large image, and video. + // More than one type can be set in the same call, but a small image must be accompanied by a large image and/or video. + // If only a large image is passed, the small image will be autogenerated. + // If only a video is passed, the large image and small will be autogenerated. + // Videos must be convertable to mp4, <=5MB, and height and width >= 448 pixels. + + // Setting the Account Picture will fail if user disallows it in PC Settings. + SetAccountPictureResult result = await UserInformation.SetAccountPicturesAsync(null, imageFile, null); + if (result == SetAccountPictureResult.Success) + { + rootPage.NotifyUser("Account picture was successfully changed.", NotifyType.StatusMessage); + } + else + { + rootPage.NotifyUser("Account picture could not be changed.", NotifyType.StatusMessage); + AccountPictureImage.Visibility = Visibility.Collapsed; + } + } + } + + private async void SetVideoButton_Click(object sender, RoutedEventArgs e) + { + FileOpenPicker videoPicker = new FileOpenPicker + { + ViewMode = PickerViewMode.Thumbnail, + SuggestedStartLocation = PickerLocationId.VideosLibrary, + FileTypeFilter = { ".mp4", ".mpeg", ".wmv", ".mov" } + }; + + StorageFile videoFile = await videoPicker.PickSingleFileAsync(); + if (videoFile != null) + { + // SetAccountPictureAsync() accepts 3 storageFile objects for setting the small image, large image, and video. + // More than one type can be set in the same call, but small image must be accompanied by a large image and/or video. + // If only a large image is passed, the small image will be autogenerated. + // If only a video is passed, the large image and small will be autogenerated. + // Videos must be convertable to mp4, <=5MB, and height and width >= 448 pixels. + + // Setting the Account Picture will fail if a user disallows it in PC Settings. + SetAccountPictureResult result = await UserInformation.SetAccountPicturesAsync(null, null, videoFile); + if (result == SetAccountPictureResult.Success) + { + rootPage.NotifyUser("Video account picture was successfully changed.", NotifyType.StatusMessage); + } + else + { + rootPage.NotifyUser("Account picture could not be changed.", NotifyType.StatusMessage); + AccountPictureImage.Visibility = Visibility.Collapsed; + } + } + } + + private async void PictureChanged(object sender, object e) + { + await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => + { + // The large picture returned by GetAccountPicture() is 448x448 pixels in size. + StorageFile image = UserInformation.GetAccountPicture(AccountPictureKind.LargeImage) as StorageFile; + if (image != null) + { + try + { + IRandomAccessStream imageStream = await image.OpenReadAsync(); + BitmapImage bitmapImage = new BitmapImage(); + bitmapImage.SetSource(imageStream); + rootPage.NotifyUser("LargeImage path = " + image.Path, NotifyType.StatusMessage); + AccountPictureImage.Source = bitmapImage; + AccountPictureImage.Visibility = Visibility.Visible; + } + catch (Exception ex) + { + rootPage.NotifyUser("Error opening stream: " + ex.ToString(), NotifyType.ErrorMessage); + } + } + else + { + rootPage.NotifyUser("Large Account Picture is not available.", NotifyType.StatusMessage); + } + }); + } + + } +} diff --git a/Samples/AccountPictureName/cs/project.json b/Samples/AccountPictureName/cs/project.json new file mode 100644 index 0000000000..c594939270 --- /dev/null +++ b/Samples/AccountPictureName/cs/project.json @@ -0,0 +1,16 @@ +{ + "dependencies": { + "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0" + }, + "frameworks": { + "uap10.0": {} + }, + "runtimes": { + "win10-arm": {}, + "win10-arm-aot": {}, + "win10-x86": {}, + "win10-x86-aot": {}, + "win10-x64": {}, + "win10-x64-aot": {} + } +} \ No newline at end of file diff --git a/Samples/AccountPictureName/js/AccountPictureName.jsproj b/Samples/AccountPictureName/js/AccountPictureName.jsproj new file mode 100644 index 0000000000..cb9c8eac79 --- /dev/null +++ b/Samples/AccountPictureName/js/AccountPictureName.jsproj @@ -0,0 +1,145 @@ + + + + + Debug + AnyCPU + + + Debug + ARM + + + Debug + x64 + + + Debug + x86 + + + Release + AnyCPU + + + Release + ARM + + + Release + x64 + + + Release + x86 + + + + {9ee3ba23-05ba-402a-a8b6-f3281c3f8b2c} + + + + 14.0 + + + + + UAP + 10.0.10240.0 + 10.0.10240.0 + $(VersionNumberMajor).$(VersionNumberMinor) + en-US + + + + Designer + + + css\default.css + + + default.html + + + + + + + images\microsoft-sdk.png + + + images\smallTile-sdk.png + + + images\splash-sdk.png + + + images\storeLogo-sdk.png + + + images\tile-sdk.png + + + images\windows-sdk.png + + + js\default.js + + + + + + + + Microsoft.WinJS.4.0\css\ui-dark.css + + + Microsoft.WinJS.4.0\css\ui-light.css + + + Microsoft.WinJS.4.0\js\en-US\ui.strings.js + + + Microsoft.WinJS.4.0\js\WinJS.intellisense-setup.js + + + Microsoft.WinJS.4.0\js\WinJS.intellisense.js + + + Microsoft.WinJS.4.0\fonts\Symbols.ttf + + + Microsoft.WinJS.4.0\js\base.js + + + Microsoft.WinJS.4.0\js\ui.js + + + sample-utils\footer.html + + + sample-utils\header.html + + + sample-utils\sample-utils.js + + + sample-utils\scenario-select.css + + + sample-utils\scenario-select.html + + + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/js/AccountPictureName.sln b/Samples/AccountPictureName/js/AccountPictureName.sln new file mode 100644 index 0000000000..2846249094 --- /dev/null +++ b/Samples/AccountPictureName/js/AccountPictureName.sln @@ -0,0 +1,24 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 for Windows +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "AccountPictureName", "AccountPictureName.jsproj", "{9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}.Release|Any CPU.Build.0 = Release|Any CPU + {9EE3BA23-05BA-402A-A8B6-F3281C3F8B2C}.Release|Any CPU.Deploy.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/AccountPictureName/js/Microsoft.WinJS.4.0/css/placeholder.txt b/Samples/AccountPictureName/js/Microsoft.WinJS.4.0/css/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/js/Microsoft.WinJS.4.0/fonts/placeholder b/Samples/AccountPictureName/js/Microsoft.WinJS.4.0/fonts/placeholder new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/js/Microsoft.WinJS.4.0/js/en-US/placeholder.txt b/Samples/AccountPictureName/js/Microsoft.WinJS.4.0/js/en-US/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/js/Package.appxmanifest b/Samples/AccountPictureName/js/Package.appxmanifest new file mode 100644 index 0000000000..0103b16e54 --- /dev/null +++ b/Samples/AccountPictureName/js/Package.appxmanifest @@ -0,0 +1,59 @@ + + + + + + + + + Account Picture Name JS Sample + Microsoft Corporation + images\storelogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AccountPictureName/js/css/placeholder.txt b/Samples/AccountPictureName/js/css/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/js/html/getAccountPicture.html b/Samples/AccountPictureName/js/html/getAccountPicture.html new file mode 100644 index 0000000000..269a568d35 --- /dev/null +++ b/Samples/AccountPictureName/js/html/getAccountPicture.html @@ -0,0 +1,40 @@ + + + + + + + + + + + +
+
+

Description:

+
+

Get the Account Picture for the current user. You can get request three different types: small, large, and video. If the size that is requested is not available an empty file is returned.

+
+
+
+ + + +
+ image holder + image holder + +
+
+
+ + + \ No newline at end of file diff --git a/Samples/AccountPictureName/js/html/setAccountPicture.html b/Samples/AccountPictureName/js/html/setAccountPicture.html new file mode 100644 index 0000000000..dbceeee048 --- /dev/null +++ b/Samples/AccountPictureName/js/html/setAccountPicture.html @@ -0,0 +1,38 @@ + + + + + + + + + + + +
+
+

Description:

+
+

Set the Account Picture image for the current logon user. The setAccountPicture method takes three parameters as input: small image, large image, and video. More than one type can be set in the same call, but a small image must be accompanied + by a large image and/or video. Pass a null for parameters you don't want to set. A change event can be listened to for Account Picture updates. The images below change by listening to the update.

+
+
+
+ + + image holder + image holder + +
+
+ + + \ No newline at end of file diff --git a/Samples/AccountPictureName/js/html/userDisplayName.html b/Samples/AccountPictureName/js/html/userDisplayName.html new file mode 100644 index 0000000000..b04d02fff0 --- /dev/null +++ b/Samples/AccountPictureName/js/html/userDisplayName.html @@ -0,0 +1,29 @@ + + + + + + + + + + + +
+
+

Description:

+
+

Get the DisplayName for the current user.

+
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/Samples/AccountPictureName/js/html/userFirstAndLastName.html b/Samples/AccountPictureName/js/html/userFirstAndLastName.html new file mode 100644 index 0000000000..dff866477e --- /dev/null +++ b/Samples/AccountPictureName/js/html/userFirstAndLastName.html @@ -0,0 +1,30 @@ + + + + + + + + + + + +
+
+

Description:

+
+

Get the First and Last Name for the current user. This is only available for Microsoft Accounts, an empty string will be returned if not available.

+
+
+ + +
+ + + \ No newline at end of file diff --git a/Samples/AccountPictureName/js/images/placeholder.txt b/Samples/AccountPictureName/js/images/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/js/js/getAccountPicture.js b/Samples/AccountPictureName/js/js/getAccountPicture.js new file mode 100644 index 0000000000..3f09d36e5d --- /dev/null +++ b/Samples/AccountPictureName/js/js/getAccountPicture.js @@ -0,0 +1,71 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/getAccountPicture.html", { + ready: function (element, options) { + hideVisibleHolders(); + document.getElementById("getSmallImage").addEventListener("click", getSmallImage, false); + document.getElementById("getLargeImage").addEventListener("click", getLargeImage, false); + document.getElementById("getVideo").addEventListener("click", getVideo, false); + } + }); + + function getSmallImage() { + hideVisibleHolders(); + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + // The small picture returned by getAccountPicture() is 96x96 pixels in size. + var image = Windows.System.UserProfile.UserInformation.getAccountPicture(Windows.System.UserProfile.AccountPictureKind.smallImage); + if (image) { + document.getElementById("smallImageHolder").style.visibility = "visible"; + document.getElementById("smallImageHolder").src = URL.createObjectURL(image, { oneTimeOnly: true }); + WinJS.log && WinJS.log("Path: " + image.path, "sample", "status"); + } else { + WinJS.log && WinJS.log("Small account picture is not available.", "sample", "status"); + } + } else { + WinJS.log && WinJS.log("Access to account picture disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } + + function getLargeImage() { + hideVisibleHolders(); + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + // The large picture returned by getAccountPicture() is 448x448 pixels in size. + var image = Windows.System.UserProfile.UserInformation.getAccountPicture(Windows.System.UserProfile.AccountPictureKind.largeImage); + if (image) { + document.getElementById("largeImageHolder").style.visibility = "visible"; + document.getElementById("largeImageHolder").src = URL.createObjectURL(image, { oneTimeOnly: true }); + WinJS.log && WinJS.log("Path: " + image.path, "sample", "status"); + } else { + WinJS.log && WinJS.log("Large account picture is not available.", "sample", "status"); + } + } else { + WinJS.log && WinJS.log("Access to account picture disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } + + function getVideo() { + hideVisibleHolders(); + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + // The video returned from getAccountPicture is 448x448 pixels in size. + var video = Windows.System.UserProfile.UserInformation.getAccountPicture(Windows.System.UserProfile.AccountPictureKind.video); + if (video) { + document.getElementById("videoHolder").style.visibility = "visible"; + document.getElementById("videoHolder").src = URL.createObjectURL(video, { oneTimeOnly: true }); + document.getElementById("videoHolder").play(); + WinJS.log && WinJS.log("Path: " + video.path, "sample", "status"); + } else { + WinJS.log && WinJS.log("Video is not available.", "sample", "status"); + } + } else { + WinJS.log && WinJS.log("Access to account picture disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } + + function hideVisibleHolders() { + document.getElementById("smallImageHolder").style.visibility = "hidden"; + document.getElementById("largeImageHolder").style.visibility = "hidden"; + document.getElementById("videoHolder").style.visibility = "hidden"; + } +})(); diff --git a/Samples/AccountPictureName/js/js/sample-configuration.js b/Samples/AccountPictureName/js/js/sample-configuration.js new file mode 100644 index 0000000000..de7c2f0022 --- /dev/null +++ b/Samples/AccountPictureName/js/js/sample-configuration.js @@ -0,0 +1,32 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + + var sampleTitle = "Account picture name JS sample"; + + var scenarios = [ + { url: "/html/userDisplayName.html", title: "Get display name" }, + { url: "/html/userFirstAndLastName.html", title: "Get first and last name" }, + { url: "/html/getAccountPicture.html", title: "Get account picture" }, + { url: "/html/setAccountPicture.html", title: "Set account picture and listen for changes" } + ]; + + WinJS.Navigation.addEventListener("navigating", function (e) { + if (e.detail && e.detail.state && e.detail.state.activatedEventArgs) { + var uri = e.detail.state.activatedEventArgs[0].uri; + if (uri && uri.schemeName === "ms-accountpictureprovider") { + // This app was activated via the Account picture apps section in Settings. + // Here you would do app-specific logic for providing the user with account picture selection UX + setImmediate(function () { + WinJS.Navigation.navigate(scenarios[3].url).done(); + }); + } + } + }); + + WinJS.Namespace.define("SdkSample", { + sampleTitle: sampleTitle, + scenarios: new WinJS.Binding.List(scenarios) + }); +})(); diff --git a/Samples/AccountPictureName/js/js/setAccountPicture.js b/Samples/AccountPictureName/js/js/setAccountPicture.js new file mode 100644 index 0000000000..12d0d68a48 --- /dev/null +++ b/Samples/AccountPictureName/js/js/setAccountPicture.js @@ -0,0 +1,102 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/setAccountPicture.html", { + ready: function (element, options) { + hideVisibleHolders(); + document.getElementById("setImage").addEventListener("click", setImage, false); + document.getElementById("setVideo").addEventListener("click", setVideo, false); + Windows.System.UserProfile.UserInformation.addEventListener("accountpicturechanged", accountPictureChanged); + } + }); + + function setImage() { + hideVisibleHolders(); + var openPicker = new Windows.Storage.Pickers.FileOpenPicker(); + openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail; + openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary; + openPicker.fileTypeFilter.replaceAll([".bmp", ".png", ".jpg", ".jpeg"]); + + openPicker.pickSingleFileAsync().done(function (file) { + if (file) { + // setAccountPictureAsync() accepts 3 storageFile objects for setting the small image, large image, and video. + // More than one type can be set in the same call, but small image must be accompanied by a large image and/or video. + // If only a large image is passed, the small image will be autogenerated. + // If only a video is passed, the large image and small will be autogenerated. + // Videos must be convertable to mp4, <=5MB, and height and width >= 448 pixels. + Windows.System.UserProfile.UserInformation.setAccountPicturesAsync(null, file, null).done(function (result) { + // A user might turn off access to the Account Picture in PC Settings, therefore we need to check the result for success. + if (result === Windows.System.UserProfile.SetAccountPictureResult.success) { + WinJS.log && WinJS.log("Successfully updated account picture.", "sample", "status"); + } else { + // A user might turn off access to the account + WinJS.log && WinJS.log("Setting account picture failed.", "sample", "status"); + } + }); + } else { + WinJS.log && WinJS.log("No image was selected.", "sample", "status"); + } + }); + } + + function setVideo() { + hideVisibleHolders(); + var openPicker = new Windows.Storage.Pickers.FileOpenPicker(); + openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail; + openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary; + openPicker.fileTypeFilter.replaceAll([".mov", ".mp4", ".wmv"]); + + openPicker.pickSingleFileAsync().done(function (file) { + if (file) { + // setAccountPictureAsync() accepts 3 storageFile objects for setting the small image, large image, and video. + // More than one type can be set in the same call, but small image must be accompanied by a large image and/or video. + // If only a large image is passed, the small image will be autogenerated. + // If only a video is passed, the large image and small will be autogenerated. + // Videos must be convertable to mp4, <=5MB, and height and width >= 448 pixels. + Windows.System.UserProfile.UserInformation.setAccountPicturesAsync(null, null, file).done(function (result) { + // A user might turn off access to the Account Picture in PC Settings, therefore we need to check the result for success. + if (result === Windows.System.UserProfile.SetAccountPictureResult.success) { + WinJS.log && WinJS.log("Successfully updated account picture.", "sample", "status"); + } else { + // A user might turn off access to the account + WinJS.log && WinJS.log("Setting account picture failed.", "sample", "status"); + } + }); + } else { + WinJS.log && WinJS.log("No video was selected.", "sample", "status"); + } + }); + } + + // This function is the handler for the AccountPictureChangedEvent, the event listener is added in initialize() below. + function accountPictureChanged() { + hideVisibleHolders(); + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + var smallImage = Windows.System.UserProfile.UserInformation.getAccountPicture(Windows.System.UserProfile.AccountPictureKind.smallImage); + if (smallImage) { + document.getElementById("smallImageHolder").src = URL.createObjectURL(smallImage, { oneTimeOnly: true }); + document.getElementById("smallImageHolder").style.visibility = "visible"; + } + var largeImage = Windows.System.UserProfile.UserInformation.getAccountPicture(Windows.System.UserProfile.AccountPictureKind.largeImage); + if (largeImage) { + document.getElementById("largeImageHolder").src = URL.createObjectURL(largeImage, { oneTimeOnly: true }); + document.getElementById("largeImageHolder").style.visibility = "visible"; + } + var video = Windows.System.UserProfile.UserInformation.getAccountPicture(Windows.System.UserProfile.AccountPictureKind.video); + if (video) { + document.getElementById("videoHolder").src = URL.createObjectURL(video, { oneTimeOnly: true }); + document.getElementById("videoHolder").style.visibility = "visible"; + } + } else { + WinJS.log && WinJS.log("Access to account picture disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } + + function hideVisibleHolders() { + document.getElementById("smallImageHolder").style.visibility = "hidden"; + document.getElementById("largeImageHolder").style.visibility = "hidden"; + document.getElementById("videoHolder").style.visibility = "hidden"; + WinJS.log && WinJS.log(" ", "sample", "status"); + } +})(); diff --git a/Samples/AccountPictureName/js/js/userDisplayName.js b/Samples/AccountPictureName/js/js/userDisplayName.js new file mode 100644 index 0000000000..040dbdfda3 --- /dev/null +++ b/Samples/AccountPictureName/js/js/userDisplayName.js @@ -0,0 +1,24 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/userDisplayName.html", { + ready: function (element, options) { + document.getElementById("getDisplayName").addEventListener("click", getDisplayName, false); + } + }); + + function getDisplayName() { + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + Windows.System.UserProfile.UserInformation.getDisplayNameAsync().done(function (result) { + if (result) { + WinJS.log && WinJS.log("Display name = " + result, "sample", "status"); + } else { + WinJS.log && WinJS.log("No display name was returned.", "sample", "status"); + } + }); + } else { + WinJS.log && WinJS.log("Access to name disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } +})(); diff --git a/Samples/AccountPictureName/js/js/userFirstAndLastName.js b/Samples/AccountPictureName/js/js/userFirstAndLastName.js new file mode 100644 index 0000000000..b2e2e66d10 --- /dev/null +++ b/Samples/AccountPictureName/js/js/userFirstAndLastName.js @@ -0,0 +1,39 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/userFirstAndLastName.html", { + ready: function (element, options) { + document.getElementById("getFirstName").addEventListener("click", getFirstName, false); + document.getElementById("getLastName").addEventListener("click", getLastName, false); + } + }); + + function getFirstName() { + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + Windows.System.UserProfile.UserInformation.getFirstNameAsync().done(function (result) { + if (result) { + WinJS.log && WinJS.log("First name = " + result, "sample", "status"); + } else { + WinJS.log && WinJS.log("No first name was returned.", "sample", "status"); + } + }); + } else { + WinJS.log && WinJS.log("Access to name disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } + + function getLastName() { + if (Windows.System.UserProfile.UserInformation.nameAccessAllowed) { + Windows.System.UserProfile.UserInformation.getLastNameAsync().done(function (result) { + if (result) { + WinJS.log && WinJS.log("Last name = " + result, "sample", "status"); + } else { + WinJS.log && WinJS.log("No last name was returned.", "sample", "status"); + } + }); + } else { + WinJS.log && WinJS.log("Access to name disabled by Privacy Setting or Group Policy.", "sample", "error"); + } + } +})(); diff --git a/Samples/AccountPictureName/js/sample-utils/placeholder.txt b/Samples/AccountPictureName/js/sample-utils/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AccountPictureName/shared/GetAccountPicture.xaml b/Samples/AccountPictureName/shared/GetAccountPicture.xaml new file mode 100644 index 0000000000..96bd210cb6 --- /dev/null +++ b/Samples/AccountPictureName/shared/GetAccountPicture.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + Get the Account Picture for the current user. + + + + + + + You can request three different types: small, large and video (dynamic image). If the type that is requested is not available, an empty file is returned. + + + + + + + + + + + + +
+
diff --git a/Samples/AdaptiveStreaming/cs/Scenario1.xaml.cs b/Samples/AdaptiveStreaming/cs/Scenario1.xaml.cs new file mode 100644 index 0000000000..02a3f803dd --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario1.xaml.cs @@ -0,0 +1,44 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using SDKTemplate; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 + +namespace AdaptiveStreaming +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class Scenario1 : Page + { + private MainPage rootPage; + + public Scenario1() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + private void btnPlay_Click(object sender, RoutedEventArgs e) + { + System.Uri manifest = new System.Uri(txtInputURL.Text); + mePlayer.Source = manifest; + } + } +} diff --git a/Samples/AdaptiveStreaming/cs/Scenario2.xaml b/Samples/AdaptiveStreaming/cs/Scenario2.xaml new file mode 100644 index 0000000000..07e9a75f19 --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario2.xaml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + 1) Creating an AdaptiveMediaSource object and binding this to a MediaElement for playback + + 2) Querying for available bitrates, setting initial bitrate and limit min/max bitrates + + 3) Registering for download requests and bitrate changes + + 4) Modify bandwidth measurement window to control responsiveness of streaming algorithm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdaptiveStreaming/cs/Scenario2.xaml.cs b/Samples/AdaptiveStreaming/cs/Scenario2.xaml.cs new file mode 100644 index 0000000000..7df3718aa6 --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario2.xaml.cs @@ -0,0 +1,212 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using SDKTemplate; + +using System; +using Windows.Media.Streaming.Adaptive; +using Windows.UI.Core; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 + +namespace AdaptiveStreaming +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class Scenario2 : Page + { + private MainPage rootPage; + AdaptiveMediaSource ams = null; //ams represents the AdaptiveMedaSource used throughout this sample + + public Scenario2() + { + this.InitializeComponent(); + } + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + private void log(string s) + { + TextBlock text = new TextBlock(); + text.Text = s; + text.TextWrapping = TextWrapping.WrapWholeWords; + stkOutput.Children.Add(text); + } + + private void btnPlay_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (string.IsNullOrEmpty(txtInputURL.Text)) + { + rootPage.NotifyUser("Specify a URI to play", NotifyType.ErrorMessage); + return; + } + + InitializeAdaptiveMediaSource(new System.Uri(txtInputURL.Text), mePlayer); + } + + async private void InitializeAdaptiveMediaSource(System.Uri uri, MediaElement m) + { + AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(uri); + if(result.Status == AdaptiveMediaSourceCreationStatus.Success) + { + ams = result.MediaSource; + m.SetMediaStreamSource(ams); + + outputBitrates(); //query for available bitrates and output to the log + txtDownloadBitrate.Text = ams.InitialBitrate.ToString(); + txtPlaybackBitrate.Text = ams.InitialBitrate.ToString(); + + //Register for download requests + ams.DownloadRequested += DownloadRequested; + + //Register for bitrate change events + ams.DownloadBitrateChanged += DownloadBitrateChanged; + ams.PlaybackBitrateChanged += PlaybackBitrateChanged; + } + else + { + rootPage.NotifyUser("Error creating the AdaptiveMediaSource\n\t" + result.Status, NotifyType.ErrorMessage); + } + } + + private void DownloadRequested(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadRequestedEventArgs args) + { + UpdateBitrateUI(txtMeasuredBandwidth, (uint)ams.InboundBitsPerSecond); + } + + private void DownloadBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadBitrateChangedEventArgs args) + { + UpdateBitrateUI(txtDownloadBitrate, args.NewValue); + } + + private void PlaybackBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourcePlaybackBitrateChangedEventArgs args) + { + UpdateBitrateUI(txtPlaybackBitrate, args.NewValue); + } + + private async void UpdateBitrateUI(TextBlock t, uint newBitrate) + { + await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() => + { + t.Text = newBitrate.ToString(); + })); + } + + private void outputBitrates() + { + if (ams != null) + { + string bitrates = "Available bitrates: "; + foreach (var b in ams.AvailableBitrates) + { + bitrates += b + " "; + } + log(bitrates); + } + else + rootPage.NotifyUser("Error: Adaptive Media Source is not initialized.", NotifyType.ErrorMessage); + } + + private void btnSetInitialBitrate_Click(object sender, RoutedEventArgs e) + { + if(ams != null) + { + uint bitrate; + if (uint.TryParse(txtInitialBitrate.Text, out bitrate)) + try { + ams.InitialBitrate = bitrate; + log("Initial bitrate set to " + bitrate); + } catch (Exception) + { + log("Initial bitrate must match a value from the manifest"); + } + else + log("Initial bitrate must be set to a positive integer"); + } + else + rootPage.NotifyUser("Error: Adaptive Media Source is not initialized.", NotifyType.ErrorMessage); + } + + private void btnSetMinBitrate_Click(object sender, RoutedEventArgs e) + { + if (ams != null) + { + uint bitrate; + if (uint.TryParse(txtMinBitrate.Text, out bitrate)) + { + uint minbitrate = ams.AvailableBitrates[0]; + foreach (var b in ams.AvailableBitrates) //iterate through the list of bitrates until the min valid bitrate is found + { + if(b >= bitrate) + { + minbitrate = b; + break; + } + } + ams.DesiredMinBitrate = minbitrate; + log("Min bitrate set to " + minbitrate); + } + else + log("Min bitrate must be a positive integer"); + } + else + rootPage.NotifyUser("Error: Adaptive Media Source is not initialized.", NotifyType.ErrorMessage); + } + + private void btnSetMaxBitrate_Click(object sender, RoutedEventArgs e) + { + if (ams != null) + { + uint bitrate; + if (uint.TryParse(txtMaxBitrate.Text, out bitrate)) + { + uint maxbitrate = ams.AvailableBitrates[ams.AvailableBitrates.Count-1]; //start with the max bitrate and work our way down + foreach (var b in ams.AvailableBitrates) //iterate through the list of bitrates until the max valid bitrate is found + { + if (b <= bitrate) + maxbitrate = b; + else + break; + } + ams.DesiredMaxBitrate = maxbitrate; + log("Max bitrate set to " + maxbitrate); + } + else + log("Max bitrate must be a positive integer"); + } + else + rootPage.NotifyUser("Error: Adaptive Media Source is not initialized.", NotifyType.ErrorMessage); + } + + private void btnSetBandwidthMeasurementWindow_Click(object sender, RoutedEventArgs e) + { + if (ams != null) + { + int windowSize; + if (int.TryParse(txtBandwidthMeasurementWindow.Text, out windowSize)) + { + ams.InboundBitsPerSecondWindow = new TimeSpan(0, 0, windowSize); + log("Bandwidth measurement window size set to " + windowSize); + } + else + log("Bandwidth measurement window size must be set to an int"); + } + else + rootPage.NotifyUser("Error: Adaptive Media Source is not initialized.", NotifyType.ErrorMessage); + } + } +} diff --git a/Samples/AdaptiveStreaming/cs/Scenario3.xaml b/Samples/AdaptiveStreaming/cs/Scenario3.xaml new file mode 100644 index 0000000000..6a4971d123 --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario3.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + Demonstrates: + + 1) Creating an AdaptiveMediaSource object and binding this to a MediaElement for playback + + 2) Registering for download success and failure events + + 3) Setting custom headers via HttpClient + + 4) Customizing resource requests + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdaptiveStreaming/cs/Scenario3.xaml.cs b/Samples/AdaptiveStreaming/cs/Scenario3.xaml.cs new file mode 100644 index 0000000000..0dabb943e0 --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario3.xaml.cs @@ -0,0 +1,108 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using SDKTemplate; + +using System; +using Windows.Media.Streaming.Adaptive; +using Windows.UI.Core; + +namespace AdaptiveStreaming +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class Scenario3 : Page + { + private MainPage rootPage; + AdaptiveMediaSource ams = null; //ams represents the AdaptiveMedaSource used throughout this sample + Windows.Web.Http.HttpClient httpClient = null; //used to customize download requests + + public Scenario3() + { + this.InitializeComponent(); + } + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + async private void log(string s) + { + await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() => + { + TextBlock text = new TextBlock(); + text.Text = s; + text.TextWrapping = TextWrapping.WrapWholeWords; + stkOutput.Children.Add(text); + })); + } + + private void btnPlay_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (string.IsNullOrEmpty(txtInputURL.Text)) + { + rootPage.NotifyUser("Specify a URI to play", NotifyType.ErrorMessage); + return; + } + + InitializeAdaptiveMediaSource(new System.Uri(txtInputURL.Text), mePlayer); + } + + async private void InitializeAdaptiveMediaSource(System.Uri uri, MediaElement m) + { + httpClient = new Windows.Web.Http.HttpClient(); + httpClient.DefaultRequestHeaders.TryAppendWithoutValidation("X-CustomHeader", "This is a custom header"); + + AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(uri, httpClient); + if (result.Status == AdaptiveMediaSourceCreationStatus.Success) + { + ams = result.MediaSource; + m.SetMediaStreamSource(ams); + + //Register for download requested event + ams.DownloadRequested += DownloadRequested; + + //Register for download success and failure events + ams.DownloadCompleted += DownloadCompleted; + ams.DownloadFailed += DownloadFailed; + } + else + { + rootPage.NotifyUser("Error creating the AdaptiveMediaSource\n\t" + result.Status, NotifyType.ErrorMessage); + } + } + + private void DownloadRequested(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadRequestedEventArgs args) + { + // rewrite key URIs to replace http:// with https:// + if (args.ResourceType == AdaptiveMediaSourceResourceType.Key) + { + string originalUri = args.ResourceUri.ToString(); + string secureUri = originalUri.Replace("http:", "https:"); + + // override the URI by setting property on the result sub object + args.Result.ResourceUri = new Uri(secureUri); + } + } + + private void DownloadCompleted(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadCompletedEventArgs args) + { + log("Download Completed. Resource Type: " + args.ResourceType + " Resource URI: " + args.ResourceUri); + } + private void DownloadFailed(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadFailedEventArgs args) + { + log("Download Failured. Resource Type: " + args.ResourceType + " Resource URI: " + args.ResourceUri + "\nHTTP Response:\n" + args.HttpResponseMessage); + } + } +} diff --git a/Samples/AdaptiveStreaming/cs/Scenario4.xaml b/Samples/AdaptiveStreaming/cs/Scenario4.xaml new file mode 100644 index 0000000000..b936b47aee --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario4.xaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + Demonstrates enabling HLS/DASH playback with PlayReady DRM + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdaptiveStreaming/cs/Scenario4.xaml.cs b/Samples/AdaptiveStreaming/cs/Scenario4.xaml.cs new file mode 100644 index 0000000000..2d30ee076f --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/Scenario4.xaml.cs @@ -0,0 +1,286 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using SDKTemplate; + +using System; +using Windows.Media.Streaming.Adaptive; +using Windows.UI.Core; + + +//Simplifies call to the MediaProtectionManager +using Windows.Media.Protection; +using Windows.Media.Protection.PlayReady; +using System.Net.Http; +using Windows.Foundation.Collections; +using System.Net.Http.Headers; +using LicenseRequest; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace AdaptiveStreaming +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class Scenario4 : Page + { + private MainPage rootPage; + AdaptiveMediaSource ams = null; //ams represents the AdaptiveMedaSource used throughout this scenario + + private MediaProtectionManager protectionManager = null; + MediaProtectionServiceCompletion serviceCompletionNotifier = null; + private string playReadyLicenseUrl = ""; + private string playReadyChallengeCustomData = ""; + + + private const int MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = -2147174251; + + public Scenario4() + { + this.InitializeComponent(); + } + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + async private void log(string s) + { + await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() => + { + TextBlock text = new TextBlock(); + text.Text = s; + text.TextWrapping = TextWrapping.WrapWholeWords; + stkOutput.Children.Add(text); + })); + } + + private void btnPlay_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (string.IsNullOrEmpty(txtInputURL.Text)) + { + rootPage.NotifyUser("Specify a URI to play", NotifyType.ErrorMessage); + return; + } + + InitializeAdaptiveMediaSource(new System.Uri(txtInputURL.Text), mePlayer); + } + + async private void InitializeAdaptiveMediaSource(System.Uri uri, MediaElement m) + { + + AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(uri); + if (result.Status == AdaptiveMediaSourceCreationStatus.Success) + { + ams = result.MediaSource; + SetUpProtectionManager(ref m); + m.SetMediaStreamSource(ams); + } + else + { + rootPage.NotifyUser("Error creating the AdaptiveMediaSource\n\t" + result.Status, NotifyType.ErrorMessage); + } + } + + private void SetUpProtectionManager(ref MediaElement m) + { + log("Enter SetUpProtectionManager"); + + log("Creating protection system mappings..."); + protectionManager = new MediaProtectionManager(); + + protectionManager.ComponentLoadFailed += new ComponentLoadFailedEventHandler(ProtectionManager_ComponentLoadFailed); + protectionManager.ServiceRequested += new ServiceRequestedEventHandler(ProtectionManager_ServiceRequested); + + //Setup PlayReady as the ProtectionSystem to use by MF. + //The code here is mandatory and should be just copied directly over to the app + Windows.Foundation.Collections.PropertySet cpSystems = new Windows.Foundation.Collections.PropertySet(); + + cpSystems.Add("{F4637010-03C3-42CD-B932-B48ADF3A6A54}", "Windows.Media.Protection.PlayReady.PlayReadyWinRTTrustedInput"); + protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionSystemIdMapping", cpSystems); + + //Use by the media stream source about how to create ITA InitData. + //See here for more detai: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376846%28v=vs.85%29.aspx + protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionSystemId", "{F4637010-03C3-42CD-B932-B48ADF3A6A54}"); + + // Setup the container GUID that's in the PPSH box + protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionContainerGuid", "{9A04F079-9840-4286-AB92-E65BE0885F95}"); + + m.ProtectionManager = protectionManager; + + log("Leave SetUpProtectionManager"); + } + + private async void ProtectionManager_ServiceRequested(MediaProtectionManager sender, ServiceRequestedEventArgs e) + { + log("Enter ProtectionManager_ServiceRequested"); + + if (e.Request is PlayReadyIndividualizationServiceRequest) + { + PlayReadyIndividualizationServiceRequest IndivRequest = e.Request as PlayReadyIndividualizationServiceRequest; + bool bResultIndiv = await ReactiveIndivRequest(IndivRequest, e.Completion); + } + else if (e.Request is PlayReadyLicenseAcquisitionServiceRequest) + { + PlayReadyLicenseAcquisitionServiceRequest licenseRequest = e.Request as PlayReadyLicenseAcquisitionServiceRequest; + LicenseAcquisitionRequest(licenseRequest, e.Completion, playReadyLicenseUrl, playReadyChallengeCustomData); + } + + log("Leave ProtectionManager_ServiceRequested"); + } + + private void ProtectionManager_ComponentLoadFailed(MediaProtectionManager sender, ComponentLoadFailedEventArgs e) + { + log("Enter ProtectionManager_ComponentLoadFailed"); + log(e.Information.ToString()); + + // List the failing components - RevocationAndRenewalInformation + for (int i = 0; i < e.Information.Items.Count; i++) + { + log(e.Information.Items[i].Name + "\nReasons=0x" + e.Information.Items[i].Reasons + "\n" + + "Renewal Id=" + e.Information.Items[i].RenewalId); + + } + e.Completion.Complete(false); + + log("Leave ProtectionManager_ComponentLoadFailed"); + } + + /// + /// Invoked to acquire the PlayReady License + /// + async void LicenseAcquisitionRequest(PlayReadyLicenseAcquisitionServiceRequest licenseRequest, MediaProtectionServiceCompletion CompletionNotifier, string Url, string ChallengeCustomData) + { + bool bResult = false; + string ExceptionMessage = string.Empty; + + try + { + if (!string.IsNullOrEmpty(Url)) + { + log("ProtectionManager PlayReady Manual License Acquisition Service Request in progress - URL: " + Url); + + if (!string.IsNullOrEmpty(ChallengeCustomData)) + { + System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); + byte[] b = encoding.GetBytes(ChallengeCustomData); + licenseRequest.ChallengeCustomData = Convert.ToBase64String(b, 0, b.Length); + } + + PlayReadySoapMessage soapMessage = licenseRequest.GenerateManualEnablingChallenge(); + + byte[] messageBytes = soapMessage.GetMessageBody(); + HttpContent httpContent = new ByteArrayContent(messageBytes); + + IPropertySet propertySetHeaders = soapMessage.MessageHeaders; + foreach (string strHeaderName in propertySetHeaders.Keys) + { + string strHeaderValue = propertySetHeaders[strHeaderName].ToString(); + + // The Add method throws an ArgumentException try to set protected headers like "Content-Type" + // so set it via "ContentType" property + if (strHeaderName.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)) + httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse(strHeaderValue); + else + httpContent.Headers.Add(strHeaderName.ToString(), strHeaderValue); + } + CommonLicenseRequest licenseAcquision = new CommonLicenseRequest(); + HttpContent responseHttpContent = await licenseAcquision.AcquireLicense(new Uri(Url), httpContent); + if (responseHttpContent != null) + { + Exception exResult = licenseRequest.ProcessManualEnablingResponse(await responseHttpContent.ReadAsByteArrayAsync()); + if (exResult != null) + { + throw exResult; + } + bResult = true; + } + else + ExceptionMessage = licenseAcquision.GetLastErrorMessage(); + } + else + { + log ("ProtectionManager PlayReady License Acquisition Service Request in progress - URL: " + licenseRequest.Uri.ToString()); + await licenseRequest.BeginServiceRequest(); + bResult = true; + } + } + catch (Exception e) + { + ExceptionMessage = e.Message; + } + + if (bResult == true) + log(!string.IsNullOrEmpty(Url) ? "ProtectionManager Manual PlayReady License Acquisition Service Request successful" : + "ProtectionManager PlayReady License Acquisition Service Request successful"); + else + log(!string.IsNullOrEmpty(Url) ? "ProtectionManager Manual PlayReady License Acquisition Service Request failed: " + ExceptionMessage : + "ProtectionManager PlayReady License Acquisition Service Request failed: " + ExceptionMessage); + CompletionNotifier.Complete(bResult); + } + /// + /// Proactive Individualization Request + /// + async void ProActiveIndivRequest() + { + PlayReadyIndividualizationServiceRequest indivRequest = new PlayReadyIndividualizationServiceRequest(); + log("ProtectionManager PlayReady ProActive Individualization Service Request in progress..."); + bool bResultIndiv = await ReactiveIndivRequest(indivRequest, null); + if (bResultIndiv == true) + log("ProtectionManager PlayReady ProActive Individualization Service Request successful"); + else + log("ProtectionManager PlayReady ProActive Individualization Service Request failed"); + + } + /// + /// Invoked to send the Individualization Request + /// + async Task ReactiveIndivRequest(PlayReadyIndividualizationServiceRequest IndivRequest, MediaProtectionServiceCompletion CompletionNotifier) + { + bool bResult = false; + Exception exception = null; + log("ProtectionManager PlayReady Individualization Service Request in progress..."); + try + { + await IndivRequest.BeginServiceRequest(); + } + catch (Exception ex) + { + exception = ex; + } + finally + { + if (exception == null) + { + bResult = true; + } + else + { + COMException comException = exception as COMException; + if (comException != null && comException.HResult == MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED) + { + IndivRequest.NextServiceRequest(); + } + } + } + if (bResult == true) + log("ProtectionManager PlayReady Individualization Service Request successful"); + else + log("ProtectionManager PlayReady Individualization Service Request failed"); + if (CompletionNotifier != null) CompletionNotifier.Complete(bResult); + return bResult; + + } + } +} diff --git a/Samples/AdaptiveStreaming/cs/project.json b/Samples/AdaptiveStreaming/cs/project.json new file mode 100644 index 0000000000..c594939270 --- /dev/null +++ b/Samples/AdaptiveStreaming/cs/project.json @@ -0,0 +1,16 @@ +{ + "dependencies": { + "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0" + }, + "frameworks": { + "uap10.0": {} + }, + "runtimes": { + "win10-arm": {}, + "win10-arm-aot": {}, + "win10-x86": {}, + "win10-x86-aot": {}, + "win10-x64": {}, + "win10-x64-aot": {} + } +} \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/AdaptiveStreaming.jsproj b/Samples/AdaptiveStreaming/js/AdaptiveStreaming.jsproj new file mode 100644 index 0000000000..10c5647ca5 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/AdaptiveStreaming.jsproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + + + Debug + ARM + + + Debug + x64 + + + Debug + x86 + + + Release + AnyCPU + + + Release + ARM + + + Release + x64 + + + Release + x86 + + + + c2adb9af-edb3-4e57-8056-9d0531d4a6b2 + + + + 14.0 + + + + + UAP + 10.0.10240.0 + 10.0.10240.0 + $(VersionNumberMajor).$(VersionNumberMinor) + en-US + + + + Designer + + + + + + default.html + + + + + + images\microsoft-sdk.png + + + images\smallTile-sdk.png + + + images\splash-sdk.png + + + images\storeLogo-sdk.png + + + images\tile-sdk.png + + + images\windows-sdk.png + + + js\default.js + + + css\default.css + + + + + + + + Microsoft.WinJS.4.0\css\ui-dark.css + + + Microsoft.WinJS.4.0\css\ui-light.css + + + Microsoft.WinJS.4.0\js\en-US\ui.strings.js + + + Microsoft.WinJS.4.0\js\WinJS.intellisense-setup.js + + + Microsoft.WinJS.4.0\js\WinJS.intellisense.js + + + Microsoft.WinJS.4.0\fonts\Symbols.ttf + + + Microsoft.WinJS.4.0\js\base.js + + + Microsoft.WinJS.4.0\js\ui.js + + + sample-utils\footer.html + + + sample-utils\header.html + + + sample-utils\sample-utils.js + + + sample-utils\scenario-select.css + + + sample-utils\scenario-select.html + + + + + + \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/AdaptiveStreaming.sln b/Samples/AdaptiveStreaming/js/AdaptiveStreaming.sln new file mode 100644 index 0000000000..0edef349c7 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/AdaptiveStreaming.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "AdaptiveStreaming", "AdaptiveStreaming.jsproj", "{C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|ARM.ActiveCfg = Debug|ARM + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|ARM.Build.0 = Debug|ARM + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|ARM.Deploy.0 = Debug|ARM + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|x64.ActiveCfg = Debug|x64 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|x64.Build.0 = Debug|x64 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|x64.Deploy.0 = Debug|x64 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|x86.ActiveCfg = Debug|x86 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|x86.Build.0 = Debug|x86 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Debug|x86.Deploy.0 = Debug|x86 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|Any CPU.Build.0 = Release|Any CPU + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|Any CPU.Deploy.0 = Release|Any CPU + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|ARM.ActiveCfg = Release|ARM + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|ARM.Build.0 = Release|ARM + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|ARM.Deploy.0 = Release|ARM + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|x64.ActiveCfg = Release|x64 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|x64.Build.0 = Release|x64 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|x64.Deploy.0 = Release|x64 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|x86.ActiveCfg = Release|x86 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|x86.Build.0 = Release|x86 + {C2ADB9AF-EDB3-4E57-8056-9D0531D4A6B2}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/AdaptiveStreaming/js/Microsoft.WinJS.4.0/css/placeholder.txt b/Samples/AdaptiveStreaming/js/Microsoft.WinJS.4.0/css/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AdaptiveStreaming/js/Microsoft.WinJS.4.0/fonts/placeholder b/Samples/AdaptiveStreaming/js/Microsoft.WinJS.4.0/fonts/placeholder new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AdaptiveStreaming/js/Microsoft.WinJS.4.0/js/en-us/placeholder.txt b/Samples/AdaptiveStreaming/js/Microsoft.WinJS.4.0/js/en-us/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AdaptiveStreaming/js/css/default.css b/Samples/AdaptiveStreaming/js/css/default.css new file mode 100644 index 0000000000..400a713e22 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/css/default.css @@ -0,0 +1,114 @@ +/* +Copyright (c) Microsoft Corporation. All rights reserved +*/ + +#header { + padding: 15px 0px 30px 52px; +} + +#statusMessage { + padding: 10px; + font-size: 12px; + font-weight: 600; +} + +#footer { + padding: 25px 10px; +} + + #footer span { + font-size: 12px; + } + + #footer .links { + color: rgb(153,153,153); + } + + #footer .links a { + color: rgb(153,153,153); + font-size: 12px; + text-decoration: none; + } + + #footer .links .pipe { + font-size: 9px; + } + +button.splitViewButton { + position: absolute; + height: 48px; + width: 48px; + min-height: 0; + min-width: 0; + padding: 0; + border: none; + margin: 0; + background-color: transparent; +} + + button.splitViewButton:hover { + background-color: rgba(255,255,255, 0.1); + } + + button.splitViewButton:active { + background-color: rgba(255,255,255, 0.2); + } + + button.splitViewButton:after { + position: relative; + font-size: 24px; + font-family: 'Segoe MDL2 Assets'; + content: "\E700"; + } + +.win-splitview-pane { + display: flex; + flex-direction: column; +} + + .win-splitview-pane #scenarioPane { + flex-grow: 1; + height: 0px; + } + +.win-splitview-pane-closed #header, +.win-splitview-pane-closed #footer { + display: none; +} + +.win-splitview-content .splitViewButton { + display: none; +} + +.hiding .win-splitview-content .splitViewButton, +.win-splitview-pane-closed .win-splitview-content .splitViewButton { + display: block; +} + +#contentWrapper { + display: flex; + flex-direction: column; + height: 100%; +} + +#statusBox { + flex-shrink: 0; +} + +#contentHost { + margin: 10px; + padding: 0px 42px 10px 42px; + height: 100%; + overflow-y: auto; +} + + #contentHost #sampleHeader, #featureLabel { + font: 20pt/24pt "Segoe UI"; + font-weight: 300; + white-space: normal; + } + + #contentHost #scenarioDescription { + font: 11pt/15pt "Segoe UI"; + font-weight: 300; + } \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/css/scenario1.css b/Samples/AdaptiveStreaming/js/css/scenario1.css new file mode 100644 index 0000000000..e3a9451a7d --- /dev/null +++ b/Samples/AdaptiveStreaming/js/css/scenario1.css @@ -0,0 +1,11 @@ +/* +Copyright (c) Microsoft Corporation. All rights reserved +*/ + +/* styles */ + +button { + width: 50px; + font-size: 12px; +} + diff --git a/Samples/AdaptiveStreaming/js/css/scenario2.css b/Samples/AdaptiveStreaming/js/css/scenario2.css new file mode 100644 index 0000000000..e385fbc2a2 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/css/scenario2.css @@ -0,0 +1,10 @@ +/* +Copyright (c) Microsoft Corporation. All rights reserved +*/ + +/* styles */ + +textarea +{ + width: 640px; +} diff --git a/Samples/AdaptiveStreaming/js/css/scenario3.css b/Samples/AdaptiveStreaming/js/css/scenario3.css new file mode 100644 index 0000000000..b5c20bc6de --- /dev/null +++ b/Samples/AdaptiveStreaming/js/css/scenario3.css @@ -0,0 +1,10 @@ +/* +Copyright (c) Microsoft Corporation. All rights reserved +*/ + +/* styles */ + +textarea +{ + width: 640px; +} \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/html/scenario1.html b/Samples/AdaptiveStreaming/js/html/scenario1.html new file mode 100644 index 0000000000..af6adfebff --- /dev/null +++ b/Samples/AdaptiveStreaming/js/html/scenario1.html @@ -0,0 +1,54 @@ + + + + + + + + + + + + + +
+
+

Description:

+
+ Demonstrates enabling basic HLS/DASH playback by setting the source of a video tag to a manifest file. +
Choose an item from the list, or provide your own URL. Then click Play. +
+
+
+ Source: + +
+ + + +
+
+ + + + +
+ +
+
+
+ + + \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/html/scenario2.html b/Samples/AdaptiveStreaming/js/html/scenario2.html new file mode 100644 index 0000000000..7456fe12a7 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/html/scenario2.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + +
+
+

Description:

+
+

+
1) Creating an AdaptiveMediaSource object and binding this to a video source for playback +
2) Querying for available bitrates, setting initial bitrate and limit min/max bitrates +
3) Registering for download requests and bitrate changes +
4) Modify bandwidth measurement window to control responsiveness of streaming algorithm +
+

+
+
+
+ +
+ + + +
+
+ + + + + + + + + + + + + +
+ Initial Bitrate:    + +
Min Bitrate:       + + +
Max Bitrate:      + + +
Bandwidth Measurement Window (in seconds): +
                        + + +
+
+ +
+ +
+ +
+
+
+ + + \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/html/scenario3.html b/Samples/AdaptiveStreaming/js/html/scenario3.html new file mode 100644 index 0000000000..427867ce84 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/html/scenario3.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + +
+
+

Description:

+
+

+
1) Creating an AdaptiveMediaSource object and binding this to a video source for playback +
2) Registering for download success and failure events +
3) Setting custom headers via HttpClient +
4) Customizing resource requests +
+

+
+
+
+ Source: + +
+ + + +
+
+ + + + + + + + + + +
+ +
+ +
+ +
+
+
+ + + \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/html/scenario4.html b/Samples/AdaptiveStreaming/js/html/scenario4.html new file mode 100644 index 0000000000..afe985cbd1 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/html/scenario4.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + +
+
+

Description:

+
+

+ Demonstrates enabling basic DASH playback with PlayReady DRM. +
Choose an item from the list, or provide your own URL. Then click Play. +

+
+
+
+ Source: + +
+ + + +
+
+ + + + + + + + + + +
+ +
+ +
+ +
+
+
+ + + \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/images/placeholder.txt b/Samples/AdaptiveStreaming/js/images/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AdaptiveStreaming/js/js/sample-configuration.js b/Samples/AdaptiveStreaming/js/js/sample-configuration.js new file mode 100644 index 0000000000..d5ceab60c3 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/js/sample-configuration.js @@ -0,0 +1,19 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + + var sampleTitle = "Adaptive Streaming"; + + var scenarios = [ + { url: "/html/scenario1.html", title: "Basic HLS/DASH Playback" }, + { url: "/html/scenario2.html", title: "Configuring HLS/DASH Playback" }, + { url: "/html/scenario3.html", title: "Customized Resource Acquisition" }, + { url: "/html/scenario4.html", title: "Playback with PlayReady DRM" } + ]; + + WinJS.Namespace.define("SdkSample", { + sampleTitle: sampleTitle, + scenarios: new WinJS.Binding.List(scenarios) + }); +})(); \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/js/scenario1.js b/Samples/AdaptiveStreaming/js/js/scenario1.js new file mode 100644 index 0000000000..9a92e5981e --- /dev/null +++ b/Samples/AdaptiveStreaming/js/js/scenario1.js @@ -0,0 +1,112 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/scenario1.html", { + ready: function (element, options) { + document.getElementById("clip_selection").addEventListener("change", onClipSelection, false); + document.getElementById("setsrc_button").addEventListener("click", setSource, false); + } + }); + + var AdaptiveStreaming = Windows.Media.Streaming.Adaptive; + var url = null; + var mediaSource = null; + + function onClipSelection() { + var src_textbox = document.getElementById("src_textbox"); + var clip_selection = document.getElementById("clip_selection"); + + for (var i = 0; i < clip_selection.options.length; ++i) { + if (clip_selection.options[i].selected) { + src_textbox.value = clip_selection.options[i].value; + } + } + } + + function mapAdaptiveMediaSourceCreationStatus(status) { + var strings = ["Success", + "ManifestDownloadFailure", + "ManifestParseFailure", + "UnsupportedManifestContentType", + "UnsupportedManifestVersion", + "UnsupportedManifestProfile", + "UnknownFailure"]; + + if (status < 0 || status > strings.length) { + return "Unknown AdaptiveMediaSourceCreationStatus"; + } + + return strings[status]; + } + + function attachMediaSource() { + try { + if (mediaSource != null) { + var vid = document.getElementById("video_player1"); + + vid.src = URL.createObjectURL(mediaSource, { oneTimeOnly: true }); + WinJS.log && WinJS.log("Set media element src to the AdaptiveMediaSource for url: " + url, "sample", "status"); + } + } catch (e) { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function onMediaSourceCreated(result) { + if (result.status === AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.success) { + + WinJS.log && WinJS.log("AdaptiveMediaSource.createFromUriAsync completed with status: " + result.status + " - " + mapAdaptiveMediaSourceCreationStatus(result.status), "sample", "status"); + mediaSource = result.mediaSource; + attachMediaSource(); + + } else { + var errorString = ""; + var httpResponseMessage = result.httpResponseMessage; + + if (httpResponseMessage != null) { + errorString = " (HTTP response: " + httpResponseMessage.statusCode + " - " + httpResponseMessage.reasonPhrase; + + if (httpResponseMessage.isSuccessStatusCode && + result.status == AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.unsupportedManifestContentType && + httpResponseMessage.content != null) { + errorString += "; Content-Type: " + httpResponseMessage.content.headers.contentType; + } + + errorString += ")"; + + } + WinJS.log && WinJS.log("Failed to create adaptive media source: " + mapAdaptiveMediaSourceCreationStatus(result.status) + errorString, "sample", "error"); + } + } + + function loadMediaSourceFromUri() { + try { + var src_textbox = document.getElementById("src_textbox"); + var vid = document.getElementById("video_player1"); + + url = new Windows.Foundation.Uri(src_textbox.value); + + mediaSource = null; + vid.removeAttribute("src"); + + WinJS.log && WinJS.log("Creating AdaptiveMediaSource for url: " + url, "sample", "status"); + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync(url).done( + function completed(result) { + onMediaSourceCreated(result); + }); + + } catch (e) { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function setSource() { + loadMediaSourceFromUri(); + } + + +})(); + + diff --git a/Samples/AdaptiveStreaming/js/js/scenario2.js b/Samples/AdaptiveStreaming/js/js/scenario2.js new file mode 100644 index 0000000000..d63fc24a1e --- /dev/null +++ b/Samples/AdaptiveStreaming/js/js/scenario2.js @@ -0,0 +1,333 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/scenario2.html", { + ready: function (element, options) { + document.getElementById("clip_selection").addEventListener("change", onClipSelection, false); + document.getElementById("setsrc_button").addEventListener("click", setSource, false); + document.getElementById("clear_button").addEventListener("click", clearEvents, false); + document.getElementById("bitrate_selection").addEventListener("change", onInitialBitrateSelection, false); + document.getElementById("min_bitrate_button").addEventListener("click", setDesiredMinBitrate, false); + document.getElementById("max_bitrate_button").addEventListener("click", setDesiredMaxBitrate, false); + document.getElementById("bw_measurement_button").addEventListener("click", setBwMeasurmentWindow, false); + } + }); + + var AdaptiveStreaming = Windows.Media.Streaming.Adaptive; + var url = null; + var mediaSource = null; + + var event_id = 1; + + var availableBitrates = null; + + var isInitialBitrateSet = false; + var initialBitrate; + + var minBitrate = null; + var maxBitrate = null; + var bwMeasurementWindow = null; + + function secondsToMiliseconds(seconds) + { + return seconds * 1000; + } + + function setBwMeasurmentWindow() { + try { + if (mediaSource != null) { + var windowSize = document.getElementById("bw_measurement_textbox").value; + if (windowSize != "") + { + mediaSource.inboundBitsPerSecondWindow = secondsToMiliseconds(windowSize); + } + else + { + //default is 30 seconds + mediaSource.inboundBitsPerSecondWindow = secondsToMiliseconds(30); + } + + bwMeasurementWindow = windowSize; + logEvent("Inbound bits per second window set to " + mediaSource.inboundBitsPerSecondWindow + " miliseconds"); + } + else + { + WinJS.log && WinJS.log("Adaptive Media Source is not set.", "sample", "error"); + } + } catch (e) + { + logEvent("EXCEPTION: " + e.toString()); + } + } + + function setDesiredMinBitrate() + { + try { + if (mediaSource != null) + { + var bitrate = document.getElementById("min_bitrate_textbox").value; + if (bitrate != "") + { + mediaSource.desiredMinBitrate = bitrate; + } + else + { + mediaSource.desiredMinBitrate = null; + } + + minBitrate = bitrate; + logEvent("Min bitrate set to " + mediaSource.desiredMinBitrate); + } + else + { + WinJS.log && WinJS.log("Adaptive Media Source is not set.", "sample", "error"); + } + } + catch (e) + { + logEvent("EXCEPTION: " + e.toString()); + } + } + + function setDesiredMaxBitrate() + { + try { + if (mediaSource != null) + { + var bitrate = document.getElementById("max_bitrate_textbox").value; + if (bitrate != "") + { + mediaSource.desiredMaxBitrate = bitrate; + } + else + { + mediaSource.desiredMaxBitrate = null; + } + maxBitrate = bitrate; + logEvent("Max bitrate set to " + mediaSource.desiredMaxBitrate); + } + else + { + WinJS.log && WinJS.log("Adaptive Media Source is not set.", "sample", "error"); + } + } + catch (e) + { + logEvent("EXCEPTION: " + e.toString()); + } + } + + function onInitialBitrateSelection() + { + isInitialBitrateSet = true; + + var initialBitrateSelection; + + var initial_bitrate_selection = document.getElementById("bitrate_selection"); + + for (var i = 0; i < initial_bitrate_selection.options.length; ++i) + { + if (initial_bitrate_selection.options[i].selected) + { + initialBitrate = initial_bitrate_selection.options[i].value; + } + } + loadMediaSourceFromUri(); + + } + + function populateInitialBitrate() + { + + var bitrate_selection = document.getElementById("bitrate_selection"); + if (bitrate_selection == null) + return; + + bitrate_selection.options.length = 1; + + if (mediaSource == null) + { + WinJS.log && WinJS.log("Adaptive Media Source is not set.", "sample", "error"); + } + else + { + availableBitrates.forEach(function (bitrate) { + var option = document.createElement("option"); + option.text = bitrate; + option.value = bitrate; + + bitrate_selection.add(option); + }); + + } + } + + function clearEvents() + { + var events_textarea = document.getElementById("events_textarea"); + events_textarea.value = ""; + event_id = 1; + } + + function logEvent(str) + { + var events_textarea = document.getElementById("events_textarea"); + if (events_textarea != null) { + events_textarea.value += "[" + event_id + "] " + str + "\n"; + event_id++; + } + } + + function onClipSelection() + { + var src_textbox = document.getElementById("src_textbox"); + var clip_selection = document.getElementById("clip_selection"); + + for (var i = 0; i < clip_selection.options.length; ++i) + { + if (clip_selection.options[i].selected) + { + src_textbox.value = clip_selection.options[i].value; + } + } + } + + function mapAdaptiveMediaSourceCreationStatus(status) + { + var strings = ["Success", + "ManifestDownloadFailure", + "ManifestParseFailure", + "UnsupportedManifestContentType", + "UnsupportedManifestVersion", + "UnsupportedManifestProfile", + "UnknownFailure"]; + + if (status < 0 || status > strings.length) + { + return "Unknown AdaptiveMediaSourceCreationStatus"; + } + + return strings[status]; + } + + function attachMediaSource() + { + try + { + if (mediaSource != null) + { + var vid = document.getElementById("video_player2"); + + vid.src = URL.createObjectURL(mediaSource, { oneTimeOnly: true }); + logEvent("Set media element src to the AdaptiveMediaSource for url: " + url); + } + } + catch (e) + { + logEvent("EXCEPTION: " + e.toString()); + } + } + + function onMediaSourceCreated(result) + { + if (result.status === AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.success) + { + + logEvent("AdaptiveMediaSource.createFromUriAsync completed with status: " + result.status + " - " + mapAdaptiveMediaSourceCreationStatus(result.status)); + mediaSource = result.mediaSource; + if (isInitialBitrateSet) + { + mediaSource.initialBitrate = initialBitrate; + isInitialBitrateSet = false; + } + + logEvent("Selecting bitrate: " + mediaSource.initialBitrate); + + var bitrates = ""; + availableBitrates = mediaSource.availableBitrates; + availableBitrates.forEach(function (bitrate) + { + if (bitrates == "") + { + bitrates = bitrate; + } else + { + bitrates += ", " + bitrate; + } + + }); + + logEvent("Available bitrates: " + bitrates); + + populateInitialBitrate(); + + mediaSource.desiredMinBitrate = minBitrate; + + mediaSource.desiredMaxBitrate = maxBitrate; + + if (bwMeasurementWindow != null) + { + mediaSource.inboundBitsPerSecondWindow = bwMeasurementWindow; + } + + attachMediaSource(); + + } + else + { + var errorString = ""; + var httpResponseMessage = result.httpResponseMessage; + + if (httpResponseMessage != null) + { + errorString = " (HTTP response: " + httpResponseMessage.statusCode + " - " + httpResponseMessage.reasonPhrase; + + if (httpResponseMessage.isSuccessStatusCode && + result.status == AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.unsupportedManifestContentType && + httpResponseMessage.content != null) + { + errorString += "; Content-Type: " + httpResponseMessage.content.headers.contentType; + } + + errorString += ")"; + + } + logEvent("Failed to create adaptive media source: " + mapAdaptiveMediaSourceCreationStatus(result.status) + errorString); + } + } + + function loadMediaSourceFromUri() + { + try + { + var src_textbox = document.getElementById("src_textbox"); + var vid = document.getElementById("video_player2"); + + url = new Windows.Foundation.Uri(src_textbox.value); + + mediaSource = null; + vid.removeAttribute("src"); + + WinJS.log && WinJS.log("Creating AdaptiveMediaSource for url: " + url, "sample", "status"); + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync(url).done( + function completed(result) + { + onMediaSourceCreated(result); + }); + + } + catch (e) + { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function setSource() + { + loadMediaSourceFromUri(); + } + + +})(); diff --git a/Samples/AdaptiveStreaming/js/js/scenario3.js b/Samples/AdaptiveStreaming/js/js/scenario3.js new file mode 100644 index 0000000000..f6a6aca7f9 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/js/scenario3.js @@ -0,0 +1,217 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/scenario3.html", { + ready: function (element, options) { + document.getElementById("clip_selection").addEventListener("change", onClipSelection, false); + document.getElementById("setsrc_button").addEventListener("click", setSource, false); + } + }); + + var AdaptiveStreaming = Windows.Media.Streaming.Adaptive; + var url = null; + var mediaSource = null; + var event_id = 1; + + function onDownloadRequested(event) + { + try + { + // rewrite key URIs to replace http:// with https:// + if (event.resourceType === AdaptiveStreaming.AdaptiveMediaSourceResourceType.key) + { + var originalUri = args.resourceUri; + var secureUri = originalUri.replace("http:", "https:"); + + //override the URI by setting property on the result sub object + args.result.resourceUri = new Windows.Foundation.Uri(secureUri); + } + } + catch (e) + { + logEvent("EXCEPTION: " + e.toString()); + } + } + + function onDownloadCompleted(event) + { + if (event.resourceByteRangeOffset == null) + { + logEvent("Download completed for " + mapResourceType(event.resourceType) + + " URI: " + event.resourceUri); + } + else + { + logEvent("Byte range completed for " + mapResourceType(event.resourceType) + + " URI: " + event.resourceUri + " offset: " + event.resourceByteRangeOffset + + " length: " + event.resourceByteRangeLength); + } + } + + function onDownloadFailed(event) + { + if (event.resourceByteRangeOffset == null) { + logEvent("Download failed for " + mapResourceType(event.resourceType) + + " URI: " + event.resourceUri); + } + else { + logEvent("Byte range failed for " + mapResourceType(event.resourceType) + + " URI: " + event.resourceUri + " offset: " + event.resourceByteRangeOffset + + " length: " + event.resourceByteRangeLength); + } + } + + function clearEvents() + { + var events_textarea = document.getElementById("events_textarea"); + events_textarea.value = ""; + event_id = 1; + } + + function logEvent(str) + { + var events_textarea = document.getElementById("events_textarea"); + if (events_textarea != null) { + events_textarea.value += "[" + event_id + "] " + str + "\n"; + event_id++; + } + } + + function onClipSelection() + { + var src_textbox = document.getElementById("src_textbox"); + var clip_selection = document.getElementById("clip_selection"); + + for (var i = 0; i < clip_selection.options.length; ++i) + { + if (clip_selection.options[i].selected) + { + src_textbox.value = clip_selection.options[i].value; + } + } + } + + function mapResourceType(resourceType) + { + var strings = ["Manifest", + "INIT segment", + "MEDIA segment", + "Key", + "IV"]; + + if (resourceType < 0 || resourceType > strings.length) + { + return "Unknown Resource Type"; + } + + return strings[resourceType]; + } + + function mapAdaptiveMediaSourceCreationStatus(status) + { + var strings = ["Success", + "ManifestDownloadFailure", + "ManifestParseFailure", + "UnsupportedManifestContentType", + "UnsupportedManifestVersion", + "UnsupportedManifestProfile", + "UnknownFailure"]; + + if (status < 0 || status > strings.length) + { + return "Unknown AdaptiveMediaSourceCreationStatus"; + } + + return strings[status]; + } + + function attachMediaSource() + { + try + { + if (mediaSource != null) + { + var vid = document.getElementById("video_player3"); + + vid.src = URL.createObjectURL(mediaSource, { oneTimeOnly: true }); + WinJS.log && WinJS.log("Set media element src to the AdaptiveMediaSource for url: " + url, "sample", "status"); + } + } + catch (e) + { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function onMediaSourceCreated(result) + { + if (result.status === AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.success) + { + + WinJS.log && WinJS.log("AdaptiveMediaSource.createFromUriAsync completed with status: " + result.status + " - " + mapAdaptiveMediaSourceCreationStatus(result.status), "sample", "status"); + mediaSource = result.mediaSource; + attachMediaSource(); + + //Register for download requested, success, and failure events + mediaSource.addEventListener("downloadrequested", onDownloadRequested, false); + mediaSource.addEventListener("downloadcompleted", onDownloadCompleted, false); + mediaSource.addEventListener("downloadfailed", onDownloadFailed, false); + } + else + { + var errorString = ""; + var httpResponseMessage = result.httpResponseMessage; + + if (httpResponseMessage != null) + { + errorString = " (HTTP response: " + httpResponseMessage.statusCode + " - " + httpResponseMessage.reasonPhrase; + + if (httpResponseMessage.isSuccessStatusCode && + result.status == AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.unsupportedManifestContentType && + httpResponseMessage.content != null) + { + errorString += "; Content-Type: " + httpResponseMessage.content.headers.contentType; + } + + errorString += ")"; + + } + WinJS.log && WinJS.log("Failed to create adaptive media source: " + mapAdaptiveMediaSourceCreationStatus(result.status) + errorString, "sample", "error"); + } + } + + function loadMediaSourceFromUri() + { + try + { + var src_textbox = document.getElementById("src_textbox"); + var vid = document.getElementById("video_player3"); + + url = new Windows.Foundation.Uri(src_textbox.value); + + mediaSource = null; + vid.removeAttribute("src"); + + WinJS.log && WinJS.log("Creating AdaptiveMediaSource for url: " + url, "sample", "status"); + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync(url).done( + function completed(result) + { + onMediaSourceCreated(result); + }); + + } + catch (e) + { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function setSource() + { + loadMediaSourceFromUri(); + } + + +})(); diff --git a/Samples/AdaptiveStreaming/js/js/scenario4.js b/Samples/AdaptiveStreaming/js/js/scenario4.js new file mode 100644 index 0000000000..911c3012f8 --- /dev/null +++ b/Samples/AdaptiveStreaming/js/js/scenario4.js @@ -0,0 +1,239 @@ +//// Copyright (c) Microsoft Corporation. All rights reserved + +(function () { + "use strict"; + var page = WinJS.UI.Pages.define("/html/scenario4.html", { + ready: function (element, options) { + document.getElementById("clip_selection").addEventListener("change", onClipSelection, false); + document.getElementById("setsrc_button").addEventListener("click", setSource, false); + } + }); + + var AdaptiveStreaming = Windows.Media.Streaming.Adaptive; + var url = null; + var mediaSource = null; + var event_id = 1; + + + function clearEvents() { + var events_textarea = document.getElementById("events_textarea"); + events_textarea.value = ""; + event_id = 1; + } + + function logEvent(str) { + var events_textarea = document.getElementById("events_textarea"); + if (events_textarea != null) { + events_textarea.value += "[" + event_id + "] " + str + "\n"; + event_id++; + } + } + + function onClipSelection() { + var src_textbox = document.getElementById("src_textbox"); + var clip_selection = document.getElementById("clip_selection"); + + for (var i = 0; i < clip_selection.options.length; ++i) { + if (clip_selection.options[i].selected) { + src_textbox.value = clip_selection.options[i].value; + } + } + } + + function mapResourceType(resourceType) { + var strings = ["Manifest", + "INIT segment", + "MEDIA segment", + "Key", + "IV"]; + + if (resourceType < 0 || resourceType > strings.length) { + return "Unknown Resource Type"; + } + + return strings[resourceType]; + } + + function mapAdaptiveMediaSourceCreationStatus(status) { + var strings = ["Success", + "ManifestDownloadFailure", + "ManifestParseFailure", + "UnsupportedManifestContentType", + "UnsupportedManifestVersion", + "UnsupportedManifestProfile", + "UnknownFailure"]; + + if (status < 0 || status > strings.length) { + return "Unknown AdaptiveMediaSourceCreationStatus"; + } + + return strings[status]; + } + + function attachMediaSource() { + try { + if (mediaSource != null) { + var vid = document.getElementById("video_player4"); + vid.src = URL.createObjectURL(mediaSource, { oneTimeOnly: true }); + WinJS.log && WinJS.log("Set media element src to the AdaptiveMediaSource for url: " + url, "sample", "status"); + } + } + catch (e) { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function onMediaSourceCreated(result) { + if (result.status === AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.success) { + + WinJS.log && WinJS.log("AdaptiveMediaSource.createFromUriAsync completed with status: " + result.status + " - " + mapAdaptiveMediaSourceCreationStatus(result.status), "sample", "status"); + mediaSource = result.mediaSource; + attachMediaSource(); + + } + else { + var errorString = ""; + var httpResponseMessage = result.httpResponseMessage; + + if (httpResponseMessage != null) { + errorString = " (HTTP response: " + httpResponseMessage.statusCode + " - " + httpResponseMessage.reasonPhrase; + + if (httpResponseMessage.isSuccessStatusCode && + result.status == AdaptiveStreaming.AdaptiveMediaSourceCreationStatus.unsupportedManifestContentType && + httpResponseMessage.content != null) { + errorString += "; Content-Type: " + httpResponseMessage.content.headers.contentType; + } + + errorString += ")"; + + } + WinJS.log && WinJS.log("Failed to create adaptive media source: " + mapAdaptiveMediaSourceCreationStatus(result.status) + errorString, "sample", "error"); + } + } + + + function loadMediaSourceFromUri() { + try { + var vid = document.getElementById("video_player4"); + var src_textbox = document.getElementById("src_textbox"); + + url = new Windows.Foundation.Uri(src_textbox.value); + + mediaSource = null; + vid.removeAttribute("src"); + + WinJS.log && WinJS.log("Creating AdaptiveMediaSource for url: " + url, "sample", "status"); + var eme = new PlayReadyManager(vid); + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync + AdaptiveStreaming.AdaptiveMediaSource.createFromUriAsync(url).done( + function completed(result) { + onMediaSourceCreated(result); + }); + + } + catch (e) { + WinJS.log && WinJS.log("EXCEPTION: " + e.toString(), "sample", "error"); + } + } + + function setSource() { + loadMediaSourceFromUri(); + } + + //============================================================================== + // EME Support + //============================================================================== + + function PlayReadyManager(vid) { + this.vid = vid; + + var that = this; + vid.addEventListener(this.NEEDKEY_EVENT, function (e) { + that.needPlayReadyKey(e); + }, false); + } + + PlayReadyManager.prototype = { + NEEDKEY_EVENT: "msneedkey", + KEYMESSAGE_EVENT: "mskeymessage", + KEYADDED_EVENT: "mskeyadded", + KEYERROR_EVENT: "mskeyerror", + KEY_SYSTEM: "com.microsoft.playready", + + needPlayReadyKey: function (e) { + var that = this; + var video = document.getElementById("video_player4"); + logEvent("Received needkey message"); + + if (!video.msKeys) { + logEvent("Creating a new MediaKeys(\"" + this.KEY_SYSTEM + "\")"); + try { + video.msSetMediaKeys(new MSMediaKeys(this.KEY_SYSTEM)); + } catch (e) { + throw "Unable to create MediaKeys(\"" + this.KEY_SYSTEM + "\"). Verify the components are installed and functional. Original error: " + e.message; + } + } else { + return; + } + + var session = video.msKeys.createSession("video/mp4", e.initData); + if (!session) { + throw "Could not create key session"; + } + + session.addEventListener(this.KEYMESSAGE_EVENT, function (e) { + logEvent("Processing key message"); + that.downloadPlayReadyKey(e.destinationURL, String.fromCharCode.apply(null, new Uint16Array(e.message.buffer)), function (data) { + session.update(data); + }); + }); + + session.addEventListener(this.KEYADDED_EVENT, function () { + logEvent("Key successfully added"); + }); + + session.addEventListener(this.KEYERROR_EVENT, function () { + throw "Unexpected 'keyerror' event from key session. Code: " + session.error.code + ", systemCode: " + session.error.systemCode; + }); + }, + + downloadPlayReadyKey: function (url, keyMessage, callback) { + logEvent("Parsing key message XML"); + var keyMessageXML = new DOMParser().parseFromString(keyMessage, "application/xml"); + + var challenge; + if (keyMessageXML.getElementsByTagName("Challenge")[0]) { + challenge = atob(keyMessageXML.getElementsByTagName("Challenge")[0].childNodes[0].nodeValue); + } else { + throw "Can not find in key message"; + } + + var headerNames = keyMessageXML.getElementsByTagName("name"); + var headerValues = keyMessageXML.getElementsByTagName("value"); + if (headerNames.length !== headerValues.length) { + throw "Mismatched header / pair in key message"; + } + + var xhr = new XMLHttpRequest(); + xhr.open("POST", url); + xhr.responseType = "arraybuffer"; + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + callback(new Uint8Array(xhr.response)); + } else { + throw "XHR failed (" + url + "). Status: " + xhr.status + " (" + xhr.statusText + ")"; + } + } + } + for (var i = 0; i < headerNames.length; i++) { + xhr.setRequestHeader(headerNames[i].childNodes[0].nodeValue, headerValues[i].childNodes[0].nodeValue); + } + + logEvent("Loading PlayReady key from: " + url); + xhr.send(challenge); + } + } + + +})(); diff --git a/Samples/AdaptiveStreaming/js/package.appxmanifest b/Samples/AdaptiveStreaming/js/package.appxmanifest new file mode 100644 index 0000000000..5ae7f6fced --- /dev/null +++ b/Samples/AdaptiveStreaming/js/package.appxmanifest @@ -0,0 +1,53 @@ + + + + + + + + + AdaptiveStreaing JS Sample + Microsoft Corporation + images\storelogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AdaptiveStreaming/js/sample-utils/placeholder.txt b/Samples/AdaptiveStreaming/js/sample-utils/placeholder.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Samples/AdvancedCasting/README.md b/Samples/AdvancedCasting/README.md new file mode 100644 index 0000000000..251400ce8c --- /dev/null +++ b/Samples/AdvancedCasting/README.md @@ -0,0 +1,65 @@ + +Advanced Casting Sample +----------- + +This sample shows how to use the APIs in the **Windows.Media.Casting** and **Windows.Media.DialProtocol** namespaces. It also illustrates how to use the **Windows.UI.ViewManagement.ProjectionManager** and **Windows.Devices.Enumeration.DevicePicker** APIs to render media on a remote device. It covers sending media to various devices- Miracast, DLNA, DIAL, and Bluetooth. For an intro to casting, see the *Basic Media Casting Sample*. + +**Scenario 1: Media Element Casting 101:** +Press the *Cast* button next to the progress bar in the video element. Select the device you'd like to cast to. + +This is an example of the built in casting that comes with the media element transport controls. This will enable casting to Miracast, DLNA, and Bluetooth devices. + +**Scenario 2: Casting APIs and a Custom Cast Button:** +Press the *Cast* button next to the progress bar in the video element. Select the device you'd like to cast to. + +This is very similar to the first scenario, however, in this case, the **Windows.Media.Casting** APIs are used manually to create a custom cast button that's then included in the media transport controls. + +**Scenario 3: DIAL Sender Universal Windows App** +For this scenario you'll need a device that supports Dial. You can set the application name and arguments in the fields provided and then use the cast button in the transport controls to launch the app on the remote device. + +In this scenario, the **Windows.Media.DialProtocol** APIs are illustrated. + +**Scenario 4: DIAL Receiver Windows Universal App** +This scenario is used to illustrate how a developer would write a universal app that supports being launched by DIAL. This app can be launched with the APIs used in Scenario 3. Currently this scenario is only valid for select Xbox configurations. + +**Scenario 5: Multi-View Media Application** +Again, the cast button is used here to send a video to a second screen. In this case, however the **Windows.UI.ViewManagement.ProjectionManager** API is used. This allows the developer to customize their second screen experience. This API works with wired monitors and Miracast devices. + +**Scenario 6: Combine Casting Methods** +This scenario brings all the prior scenarios together and shows how to use them all at the same time in order to reach the widest set of devices. **Windows.Devices.Enumeration.DevicePicker** is used to build a picker to show all the different devices in one place. + +Related topics +-------------- + +[Windows.Media.Casting namespace](https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.casting.aspx) +[Windows.Media.DialProtocol namespace](https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.dialprotocol.aspx) +[Windows.UI.ViewManagement.ProjectionManager API](https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.viewmanagement.projectionmanager.aspx) +[Windows.Devices.Enumeration.DevicePicker API](https://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.enumeration.devicepicker.aspx) + +System requirements +----------------------------- + +Client: +Windows 10 +Windows Phone 10 + +Build the sample +---------------- + +1. Start Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**. +2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the language you desire - either C++, C\#, or JavaScript. Double-click the Visual Studio 2015 Solution (.sln) file. +3. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**. + +Run the sample +-------------- + +The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it. + +**Deploying the sample** +1. Select **Build** \> **Deploy Solution**. + +**Deploying and running the sample** +1. To debug the sample and then run it, press F5 or select **Debug** \> **Start Debugging**. To run the sample without debugging, press Ctrl+F5 or select**Debug** \> **Start Without Debugging**. + diff --git a/Samples/AdvancedCasting/cs/01_MediaElement.xaml b/Samples/AdvancedCasting/cs/01_MediaElement.xaml new file mode 100644 index 0000000000..9522486ebb --- /dev/null +++ b/Samples/AdvancedCasting/cs/01_MediaElement.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/01_MediaElement.xaml.cs b/Samples/AdvancedCasting/cs/01_MediaElement.xaml.cs new file mode 100644 index 0000000000..a453b92d27 --- /dev/null +++ b/Samples/AdvancedCasting/cs/01_MediaElement.xaml.cs @@ -0,0 +1,71 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Data.Azure; +using ScreenCasting.Data.Common; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace ScreenCasting +{ + public sealed partial class Scenario01 : Page + { + private MainPage rootPage; + private VideoMetaData video; + public Scenario01() + { + this.InitializeComponent(); + + rootPage = MainPage.Current; + + //Subscribe to player events + player.MediaOpened += Player_MediaOpened; + player.MediaFailed += Player_MediaFailed; + player.CurrentStateChanged += Player_CurrentStateChanged; + + // Get a video + AzureDataProvider dataProvider = new AzureDataProvider(); + video = dataProvider.GetRandomVideo(); + this.player.Source = video.VideoLink; + this.LicenseText.Text = "License: " + video.License; + + //Set the source on the MediaElement + rootPage.NotifyUser(string.Format("Opening '{0}'", video.Title), NotifyType.StatusMessage); + + // Use the compat version of the transport controls + this.player.TransportControls.IsCompact = true; + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + #region Media Element Methods + private void Player_CurrentStateChanged(object sender, RoutedEventArgs e) + { + if (this.player.CurrentState != Windows.UI.Xaml.Media.MediaElementState.Closed) + rootPage.NotifyUser(string.Format("{0} '{1}'", this.player.CurrentState, video.Title), NotifyType.StatusMessage); + } + private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Failed to load '{0}', {1}", video.Title, e.ErrorMessage), NotifyType.ErrorMessage); + } + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Openend '{0}'", video.Title), NotifyType.StatusMessage); + } + + #endregion + + } +} diff --git a/Samples/AdvancedCasting/cs/02_Casting_API_CastButton.xaml b/Samples/AdvancedCasting/cs/02_Casting_API_CastButton.xaml new file mode 100644 index 0000000000..52d8135bf9 --- /dev/null +++ b/Samples/AdvancedCasting/cs/02_Casting_API_CastButton.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/02_Casting_API_CastButton.xaml.cs b/Samples/AdvancedCasting/cs/02_Casting_API_CastButton.xaml.cs new file mode 100644 index 0000000000..34fc458f02 --- /dev/null +++ b/Samples/AdvancedCasting/cs/02_Casting_API_CastButton.xaml.cs @@ -0,0 +1,201 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Controls; +using ScreenCasting.Data.Azure; +using ScreenCasting.Data.Common; +using System; +using Windows.Devices.Enumeration; +using Windows.Foundation; +using Windows.Media.Casting; +using Windows.UI; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Imaging; +using Windows.UI.Xaml.Navigation; + +namespace ScreenCasting +{ + public sealed partial class Scenario02 : Page + { + private MainPage rootPage; + private CastingDevicePicker picker = null; + private VideoMetaData video = null; + private CastingConnection connection; + public Scenario02() + { + this.InitializeComponent(); + + rootPage = MainPage.Current; + + //Subscribe to player events + player.MediaOpened += Player_MediaOpened; + player.MediaFailed += Player_MediaFailed; + player.CurrentStateChanged += Player_CurrentStateChanged; + + // Get an Azure hosted video + AzureDataProvider dataProvider = new AzureDataProvider(); + video = dataProvider.GetRandomVideo(); + + //Set the source on the player + rootPage.NotifyUser(string.Format("Opening '{0}'", video.Title), NotifyType.StatusMessage); + player.Source = video.VideoLink; + this.LicenseText.Text = "License: " + video.License; + + //Subscribe for the clicked event on the custom cast button + ((MediaTransportControlsWithCustomCastButton)this.player.TransportControls).CastButtonClicked += TransportControls_CastButtonClicked; + + // Instantiate the Device Picker + picker = new CastingDevicePicker(); + + // Generate the filter based on the content in the MediaElement + picker.Filter.SupportedCastingSources.Add(player.GetAsCastingSource()); + + //Hook up device selected event + picker.CastingDeviceSelected += Picker_CastingDeviceSelected; + + //Hook up device disconnected event + picker.CastingDevicePickerDismissed += Picker_CastingDevicePickerDismissed; + + //Set the Appearence of the picker + picker.Appearance.BackgroundColor = Colors.Black; + picker.Appearance.ForegroundColor = Colors.White; + picker.Appearance.AccentColor = Colors.Gray; + + picker.Appearance.SelectedAccentColor = Colors.Gray; + + picker.Appearance.SelectedForegroundColor = Colors.White; + picker.Appearance.SelectedBackgroundColor = Colors.Black; + } + + private void TransportControls_CastButtonClicked(object sender, EventArgs e) + { + rootPage.NotifyUser("Custom Cast Button Clicked", NotifyType.StatusMessage); + + //Pause Current Playback + player.Pause(); + + //Get the custom transport controls + MediaTransportControlsWithCustomCastButton mtc = (MediaTransportControlsWithCustomCastButton)this.player.TransportControls; + + //Retrieve the location of the casting button + GeneralTransform transform = mtc.CastButton.TransformToVisual(Window.Current.Content as UIElement); + Point pt = transform.TransformPoint(new Point(0, 0)); + + //Show the picker above our custom cast button + picker.Show(new Rect(pt.X, pt.Y, mtc.CastButton.ActualWidth, mtc.CastButton.ActualHeight), Windows.UI.Popups.Placement.Above); + } + + private async void Picker_CastingDevicePickerDismissed(CastingDevicePicker sender, object args) + { + // This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + player.Play(); + }); + } + private async void Picker_CastingDeviceSelected(CastingDevicePicker sender, CastingDeviceSelectedEventArgs args) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + try + { + rootPage.NotifyUser(string.Format("Picker DeviceSelected event fired for device '{0}'", args.SelectedCastingDevice.FriendlyName), NotifyType.StatusMessage); + + //DateTime t1 = DateTime.Now; + //DeviceInformation mydevice = await DeviceInformation.CreateFromIdAsync(args.SelectedCastingDevice.Id); + //DateTime t2 = DateTime.Now; + + //TimeSpan ts = new TimeSpan(t2.Ticks - t1.Ticks); + + //System.Diagnostics.Debug.WriteLine(string.Format("DeviceInformation.CreateFromIdAsync took '{0} seconds'", ts.TotalSeconds)); + + //Create a casting conneciton from our selected casting device + rootPage.NotifyUser(string.Format("Creating connection for '{0}'", args.SelectedCastingDevice.FriendlyName), NotifyType.StatusMessage); + connection = args.SelectedCastingDevice.CreateCastingConnection(); + + //Hook up the casting events + connection.ErrorOccurred += Connection_ErrorOccurred; + connection.StateChanged += Connection_StateChanged; + + // Get the casting source from the MediaElement + CastingSource source = null; + + try + { + // Get the casting source from the Media Element + source = player.GetAsCastingSource(); + + // Start Casting + rootPage.NotifyUser(string.Format("Starting casting to '{0}'", args.SelectedCastingDevice.FriendlyName), NotifyType.StatusMessage); + CastingConnectionErrorStatus status = await connection.RequestStartCastingAsync(source); + + if (status == CastingConnectionErrorStatus.Succeeded) + { + player.Play(); + rootPage.NotifyUser(string.Format("Starting casting to '{0}'", args.SelectedCastingDevice.FriendlyName), NotifyType.StatusMessage); + } + + } + catch + { + rootPage.NotifyUser(string.Format("Failed to get casting source for video '{0}'", video.Title), NotifyType.ErrorMessage); + } + } + catch (Exception ex) + { + UnhandledExceptionPage.ShowUnhandledException(ex); + } + }); + } + + #region Casting Connection Status Methods + private async void Connection_StateChanged(CastingConnection sender, object args) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Casting Connection State Changed: " + sender.State, NotifyType.StatusMessage); + }); + } + private async void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Connection Error Occured: " + args.Message, NotifyType.ErrorMessage); + }); + } + + #endregion + + + #region Media Element Status Methods + private void Player_CurrentStateChanged(object sender, RoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("{0} '{1}'", this.player.CurrentState, video.Title), NotifyType.StatusMessage); + } + private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Failed to load '{0}'", video.Title), NotifyType.ErrorMessage); + } + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Openend '{0}'", video.Title), NotifyType.StatusMessage); + } + + + #endregion + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + } +} diff --git a/Samples/AdvancedCasting/cs/03_DIAL_Sender_API.xaml b/Samples/AdvancedCasting/cs/03_DIAL_Sender_API.xaml new file mode 100644 index 0000000000..03e9d01c49 --- /dev/null +++ b/Samples/AdvancedCasting/cs/03_DIAL_Sender_API.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/03_DIAL_Sender_API.xaml.cs b/Samples/AdvancedCasting/cs/03_DIAL_Sender_API.xaml.cs new file mode 100644 index 0000000000..68c5a37ff7 --- /dev/null +++ b/Samples/AdvancedCasting/cs/03_DIAL_Sender_API.xaml.cs @@ -0,0 +1,275 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Controls; +using ScreenCasting.Data.Azure; +using ScreenCasting.Data.Common; +using System; +using Windows.Devices.Enumeration; +using Windows.Foundation; +using Windows.Media.DialProtocol; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace ScreenCasting +{ + public sealed partial class Scenario03 : Page + { + private MainPage rootPage; + private DialDevicePicker picker = null; + private VideoMetaData video = null; + private DialDevice activeDialDevice = null; + private DeviceInformation activeDeviceInformation = null; + + + public Scenario03() + { + this.InitializeComponent(); + + rootPage = MainPage.Current; + + //Subscribe to player events + player.MediaOpened += Player_MediaOpened; + player.MediaFailed += Player_MediaFailed; + player.CurrentStateChanged += Player_CurrentStateChanged; + + // Get an Azure hosted video + AzureDataProvider dataProvider = new AzureDataProvider(); + video = dataProvider.GetRandomVideo(); + + //Set the source on the player + rootPage.NotifyUser(string.Format("Opening '{0}'", video.Title), NotifyType.StatusMessage); + this.player.Source = video.VideoLink; + + //Subscribe for the clicked event on the custom cast button + ((MediaTransportControlsWithCustomCastButton)this.player.TransportControls).CastButtonClicked += TransportControls_CastButtonClicked; + + //Configure the DIAL launch arguments for the current video + this.dial_launch_args_textbox.Text = string.Format("v={0}&t=0&pairingCode=E4A8136D-BCD3-45F4-8E49-AE01E9A46B5F", video.Id); + + //Subscribe for the clicked event on the custom cast button + ((MediaTransportControlsWithCustomCastButton)this.player.TransportControls).CastButtonClicked += TransportControls_CastButtonClicked; + + // Instantiate the Device Picker + picker = new DialDevicePicker(); + + //Add the DIAL Filter, so that the application only shows DIAL devices that have + // the application installed or advertise that they can install them. + picker.Filter.SupportedAppNames.Add(this.dial_appname_textbox.Text); + + //Hook up device selected event + picker.DialDeviceSelected += Picker_DeviceSelected; + + //Hook up the picker disconnected event + picker.DisconnectButtonClicked += Picker_DisconnectButtonClicked; + + //Hook up the picker dismissed event + picker.DialDevicePickerDismissed += Picker_DevicePickerDismissed; + } + private void TransportControls_CastButtonClicked(object sender, EventArgs e) + { + rootPage.NotifyUser("Show Device Picker Button Clicked", NotifyType.StatusMessage); + + //Pause Current Playback + player.Pause(); + + //Get the custom transport controls + MediaTransportControlsWithCustomCastButton mtc = (MediaTransportControlsWithCustomCastButton)this.player.TransportControls; + //Retrieve the location of the casting button + GeneralTransform transform = mtc.CastButton.TransformToVisual(Window.Current.Content as UIElement); + Point pt = transform.TransformPoint(new Point(0, 0)); + + //Show the picker above our Show Device Picker button + picker.Show(new Rect(pt.X, pt.Y, mtc.CastButton.ActualWidth, mtc.CastButton.ActualHeight), Windows.UI.Popups.Placement.Above); + + try + { + if (activeDialDevice != null) + picker.SetDisplayStatus(activeDialDevice, DialDeviceDisplayStatus.Connected); + } + catch (Exception ex) + { + UnhandledExceptionPage.ShowUnhandledException(ex); + } + } + + #region Device Picker Methods + + private async void Picker_DevicePickerDismissed(DialDevicePicker sender, object args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + try + { + rootPage.NotifyUser(string.Format("Picker DevicePickerDismissed event fired for device"), NotifyType.StatusMessage); + + if (activeDialDevice != null) + { + // Resume video playback + this.player.Play(); + } + } + catch (Exception ex) + { + UnhandledExceptionPage.ShowUnhandledException(ex); + } + }); + } + + private async void Picker_DisconnectButtonClicked(DialDevicePicker sender, DialDisconnectButtonClickedEventArgs args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + try + { + rootPage.NotifyUser(string.Format("Picker DisconnectButtonClicked event fired for device '{0}'", activeDeviceInformation.Name), NotifyType.StatusMessage); + + // Get the DialDevice instance for the selected device + DialDevice selectedDialDevice = await DialDevice.FromIdAsync(args.Device.Id); + // Update the picker status + picker.SetDisplayStatus(selectedDialDevice, DialDeviceDisplayStatus.Connecting); + + DialApp app = selectedDialDevice.GetDialApp(this.dial_appname_textbox.Text); + + //Get the current application state + //DialAppStateDetails stateDetails = await app.GetAppStateAsync(); + + DialAppStopResult result = await app.StopAsync(); + + if (result == DialAppStopResult.Stopped) + { + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser("Application stopped successfully.", NotifyType.StatusMessage); + picker.SetDisplayStatus(args.Device, DialDeviceDisplayStatus.Disconnected); + activeDialDevice = null; + activeDeviceInformation = null; + picker.Hide(); + } + else + { + if (result == DialAppStopResult.StopFailed || result == DialAppStopResult.NetworkFailure) + { + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser(string.Format("Error occured trying to stop application. Status: '{0}'", result.ToString()), NotifyType.StatusMessage); + picker.SetDisplayStatus(args.Device, DialDeviceDisplayStatus.Error); + } + else //in case of DialAppStopResult.OperationNotSupported, there is not much more you can do. You could implement your own + // mechanism to stop the application on that device. + { + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser(string.Format("Stop is not supported by device: '{0}'", activeDeviceInformation.Name), NotifyType.ErrorMessage); + activeDialDevice = null; + activeDeviceInformation = null; + + } + } + } + catch (Exception ex) + { + UnhandledExceptionPage.ShowUnhandledException(ex); + } + + }); + } + + private async void Picker_DeviceSelected(DialDevicePicker sender, DialDeviceSelectedEventArgs args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + try { + rootPage.NotifyUser(string.Format("Picker DeviceSelected event fired"), NotifyType.StatusMessage); + + // Set the status to connecting + picker.SetDisplayStatus(args.SelectedDialDevice, DialDeviceDisplayStatus.Connecting); + + rootPage.NotifyUser(string.Format("Resolving DialDevice'"), NotifyType.StatusMessage); + + //Get the DialApp object for the specific application on the selected device + DialApp app = args.SelectedDialDevice.GetDialApp(this.dial_appname_textbox.Text); + + if (app == null) + { + //Try to create a DIAL device. If it doesn't succeed, the selected device does not support DIAL. + //rootPage.NotifyUser(string.Format("'{0}' cannot find app with ID '{1}'", selectedDeviceInformation.Name, this.dial_appname_textbox.Text), NotifyType.StatusMessage); + picker.SetDisplayStatus(args.SelectedDialDevice, DialDeviceDisplayStatus.Error); + } + else + { + rootPage.NotifyUser(string.Format("Attempting to launch '{0}'", app.AppName), NotifyType.StatusMessage); + //Launch the application on the 1st screen device + DialAppLaunchResult result = await app.RequestLaunchAsync(this.dial_launch_args_textbox.Text); + + //Verify to see whether the application was launched + if (result == DialAppLaunchResult.Launched) + { + rootPage.NotifyUser(string.Format("Launched '{0}'", app.AppName), NotifyType.StatusMessage); + activeDialDevice = args.SelectedDialDevice; + DeviceInformation selectedDeviceInformation = await DeviceInformation.CreateFromIdAsync(args.SelectedDialDevice.Id); + + activeDeviceInformation = selectedDeviceInformation; + + //This is where you will need to add you application specific communication between your 1st and 2nd screen applications + //... + //... + //... + + picker.SetDisplayStatus(activeDialDevice, DialDeviceDisplayStatus.Connected); + picker.Hide(); + } + else + { + rootPage.NotifyUser(string.Format("Attempting to launch '{0}'", app.AppName), NotifyType.StatusMessage); + picker.SetDisplayStatus(args.SelectedDialDevice, DialDeviceDisplayStatus.Error); + } + } + } + catch (Exception ex) + { + UnhandledExceptionPage.ShowUnhandledException(ex); + } + }); + } + + #endregion + + #region Media Element Status Methods + private void Player_CurrentStateChanged(object sender, RoutedEventArgs e) + { + // Update status + rootPage.NotifyUser(string.Format("{0} '{1}'", this.player.CurrentState, video.Title), NotifyType.StatusMessage); + } + private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e) + { + // Update status + rootPage.NotifyUser(string.Format("Failed to load '{0}'", video.Title), NotifyType.ErrorMessage); + } + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + // Update status + rootPage.NotifyUser(string.Format("Openend '{0}'", video.Title), NotifyType.StatusMessage); + // Start playback + player.Play(); + } + + #endregion + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + } +} diff --git a/Samples/AdvancedCasting/cs/04_DIAL_Receiver_App.xaml b/Samples/AdvancedCasting/cs/04_DIAL_Receiver_App.xaml new file mode 100644 index 0000000000..dd3eb15857 --- /dev/null +++ b/Samples/AdvancedCasting/cs/04_DIAL_Receiver_App.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/04_DIAL_Receiver_App.xaml.cs b/Samples/AdvancedCasting/cs/04_DIAL_Receiver_App.xaml.cs new file mode 100644 index 0000000000..7f634e809a --- /dev/null +++ b/Samples/AdvancedCasting/cs/04_DIAL_Receiver_App.xaml.cs @@ -0,0 +1,117 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Data.Azure; +using ScreenCasting.Data.Common; +using ScreenCasting.Util; +using System; +using Windows.ApplicationModel.Activation; +using Windows.Storage; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace ScreenCasting +{ + public sealed partial class Scenario04 : Page + { + private MainPage rootPage; + private VideoMetaData video = null; + private TimeSpan originalPosition = new TimeSpan(0); + public Scenario04() + { + this.InitializeComponent(); + + rootPage = MainPage.Current; + rootPage.SizeChanged += RootPage_SizeChanged; + } + + protected async override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + + //Subscribe to player events + player.MediaOpened += Player_MediaOpened; + player.MediaFailed += Player_MediaFailed; + player.CurrentStateChanged += Player_CurrentStateChanged; + player.MediaEnded += Player_MediaEnded; + + if (e.Parameter is DialReceiverActivatedEventArgs) + { + DialReceiverActivatedEventArgs activationArgs = (DialReceiverActivatedEventArgs)e.Parameter; + + //Parse the DIAL arguments from the activation arguments + DialLaunchArguments dialArgs = DialLaunchArguments.Parse(activationArgs.Arguments); + + // Get the list of available Azure videos. + AzureDataProvider dataProvider = new AzureDataProvider(); + // Get the vide that is playing + video = dataProvider.GetFromID(dialArgs.VideoId); + //Set the source on the player + rootPage.NotifyUser(string.Format("Opening '{0}'", video.Title), NotifyType.StatusMessage); + this.player.Source = video.VideoLink; + this.LicenseText.Text = "License: " + video.License; + + player.Position = dialArgs.Position; + } + else + { + StorageFile localVideo = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/casting.mp4")); + var stream = await localVideo.OpenAsync(FileAccessMode.Read); + this.player.SetSource(stream, localVideo.FileType); + } + } + + private void Player_MediaEnded(object sender, RoutedEventArgs e) + { + if (video == null) + { + this.player.Position = new TimeSpan(0); + this.player.Play(); + } + } + + private void RootPage_SizeChanged(object sender, SizeChangedEventArgs e) + { + this.player.Height = this.Height; + this.player.Width = this.Width; + } + + #region MediaElement Status Changes + private void Player_CurrentStateChanged(object sender, RoutedEventArgs e) + { + if (video == null) + rootPage.NotifyUser(string.Format("{0}", this.player.CurrentState), NotifyType.StatusMessage); + else + rootPage.NotifyUser(string.Format("{0} '{1}'", this.player.CurrentState, video.Title), NotifyType.StatusMessage); + } + + private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e) + { + if (video == null) + rootPage.NotifyUser(string.Format("Failed to load"), NotifyType.ErrorMessage); + else + rootPage.NotifyUser(string.Format("Failed to load '{0}'", video.Title), NotifyType.ErrorMessage); + } + + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + if (video == null) + rootPage.NotifyUser(string.Format("Openend"), NotifyType.StatusMessage); + else + rootPage.NotifyUser(string.Format("Openend '{0}'", "Title"), NotifyType.StatusMessage); + + player.Play(); + } + + #endregion + } +} diff --git a/Samples/AdvancedCasting/cs/05_Multi_View_Media_Application.xaml b/Samples/AdvancedCasting/cs/05_Multi_View_Media_Application.xaml new file mode 100644 index 0000000000..a53776d853 --- /dev/null +++ b/Samples/AdvancedCasting/cs/05_Multi_View_Media_Application.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/05_Multi_View_Media_Application.xaml.cs b/Samples/AdvancedCasting/cs/05_Multi_View_Media_Application.xaml.cs new file mode 100644 index 0000000000..555614d393 --- /dev/null +++ b/Samples/AdvancedCasting/cs/05_Multi_View_Media_Application.xaml.cs @@ -0,0 +1,263 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Controls; +using ScreenCasting.Data.Azure; +using ScreenCasting.Data.Common; +using ScreenCasting.Util; +using System; +using Windows.ApplicationModel.Core; +using Windows.Devices.Enumeration; +using Windows.Foundation; +using Windows.UI.Core; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Imaging; +using Windows.UI.Xaml.Navigation; + +namespace ScreenCasting +{ + public sealed partial class Scenario05 : Page + { + private MainPage rootPage; + private DevicePicker picker; + private VideoMetaData video = null; + ProjectionViewBroker pvb = new ProjectionViewBroker(); + DeviceInformation activeDevice = null; + + int thisViewId; + + public Scenario05() + { + this.InitializeComponent(); + + rootPage = MainPage.Current; + + //Subscribe to player events + player.MediaOpened += Player_MediaOpened; + player.MediaFailed += Player_MediaFailed; + player.CurrentStateChanged += Player_CurrentStateChanged; + + // Get an Azure hosted video + AzureDataProvider dataProvider = new AzureDataProvider(); + video = dataProvider.GetRandomVideo(); + + //Set the source on the player + rootPage.NotifyUser(string.Format("Opening '{0}'", video.Title), NotifyType.StatusMessage); + this.player.Source = video.VideoLink; + this.LicenseText.Text = "License: " + video.License; + + //Subscribe for the clicked event on the custom cast button + ((MediaTransportControlsWithCustomCastButton)this.player.TransportControls).CastButtonClicked += TransportControls_CastButtonClicked; + + // Instantiate the Device Picker + picker = new DevicePicker (); + + // Get the device selecter for Miracast devices + picker.Filter.SupportedDeviceSelectors.Add(ProjectionManager.GetDeviceSelector()); + + //Hook up device selected event + picker.DeviceSelected += Picker_DeviceSelected; + + //Hook up device disconnected event + picker.DisconnectButtonClicked += Picker_DisconnectButtonClicked; + + //Hook up picker dismissed event + picker.DevicePickerDismissed += Picker_DevicePickerDismissed; + + // Hook up the events that are received when projection is stoppped + pvb.ProjectionStopping += Pvb_ProjectionStopping; + } + + private void TransportControls_CastButtonClicked(object sender, EventArgs e) + { + rootPage.NotifyUser("Custom Cast Button Clicked", NotifyType.StatusMessage); + + //Pause Current Playback + player.Pause(); + + //Get the custom transport controls + MediaTransportControlsWithCustomCastButton mtc = (MediaTransportControlsWithCustomCastButton)this.player.TransportControls; + + //Retrieve the location of the casting button + GeneralTransform transform = mtc.CastButton.TransformToVisual(Window.Current.Content as UIElement); + Point pt = transform.TransformPoint(new Point(0, 0)); + + //Show the picker above our custom cast button + picker.Show(new Rect(pt.X, pt.Y, mtc.CastButton.ActualWidth, mtc.CastButton.ActualHeight), Windows.UI.Popups.Placement.Above); + } + private async void Picker_DeviceSelected(DevicePicker sender, DeviceSelectedEventArgs args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + try + { + // Set status to Connecting + picker.SetDisplayStatus(args.SelectedDevice, "Connecting", DevicePickerDisplayStatusOptions.ShowProgress); + + // Getting the selected device improves debugging + DeviceInformation selectedDevice = args.SelectedDevice; + + thisViewId = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Id; + + // If projection is already in progress, then it could be shown on the monitor again + // Otherwise, we need to create a new view to show the presentation + if (rootPage.ProjectionViewPageControl == null) + { + // First, create a new, blank view + var thisDispatcher = Window.Current.Dispatcher; + await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + // ViewLifetimeControl is a wrapper to make sure the view is closed only + // when the app is done with it + rootPage.ProjectionViewPageControl = ViewLifetimeControl.CreateForCurrentView(); + + // Assemble some data necessary for the new page + pvb.MainPageDispatcher = thisDispatcher; + pvb.ProjectionViewPageControl = rootPage.ProjectionViewPageControl; + pvb.MainViewId = thisViewId; + + // Display the page in the view. Note that the view will not become visible + // until "StartProjectingAsync" is called + var rootFrame = new Frame(); + rootFrame.Navigate(typeof(ProjectionViewPage), pvb); + Window.Current.Content = rootFrame; + + Window.Current.Activate(); + }); + } + + try + { + // Start/StopViewInUse are used to signal that the app is interacting with the + // view, so it shouldn't be closed yet, even if the user loses access to it + rootPage.ProjectionViewPageControl.StartViewInUse(); + + try + { + await ProjectionManager.StartProjectingAsync(rootPage.ProjectionViewPageControl.Id, thisViewId, selectedDevice); + + } + catch (Exception ex) + { + if (!ProjectionManager.ProjectionDisplayAvailable || pvb.ProjectedPage == null) + throw ex; + } + + // ProjectionManager currently can throw an exception even when projection has started.\ + // Re-throw the exception when projection has not been started after calling StartProjectingAsync + if (ProjectionManager.ProjectionDisplayAvailable && pvb.ProjectedPage != null) + { + this.player.Pause(); + await pvb.ProjectedPage.SetMediaSource(this.player.Source, this.player.Position); + activeDevice = selectedDevice; + // Set status to Connected + picker.SetDisplayStatus(args.SelectedDevice, "Connected", DevicePickerDisplayStatusOptions.ShowDisconnectButton); + picker.Hide(); + } + else + { + rootPage.NotifyUser(string.Format("Projection has failed to '{0}'", selectedDevice.Name), NotifyType.ErrorMessage); + // Set status to Failed + picker.SetDisplayStatus(args.SelectedDevice, "Connection Failed", DevicePickerDisplayStatusOptions.ShowRetryButton); + } + } + catch (Exception) + { + rootPage.NotifyUser(string.Format("Projection has failed to '{0}'", selectedDevice.Name), NotifyType.ErrorMessage); + // Set status to Failed + try { picker.SetDisplayStatus(args.SelectedDevice, "Connection Failed", DevicePickerDisplayStatusOptions.ShowRetryButton); } catch { } + } + } + catch (Exception ex) + { + UnhandledExceptionPage.ShowUnhandledException(ex); + } + }); + } + private async void Picker_DevicePickerDismissed(DevicePicker sender, object args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + if (activeDevice == null) + { + player.Play(); + } + }); + } + private async void Picker_DisconnectButtonClicked(DevicePicker sender, DeviceDisconnectButtonClickedEventArgs args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Disconnect Button clicked", NotifyType.StatusMessage); + //Update the display status for the selected device. + sender.SetDisplayStatus(args.Device, "Disconnecting", DevicePickerDisplayStatusOptions.ShowProgress); + + if (this.pvb.ProjectedPage != null) + this.pvb.ProjectedPage.StopProjecting(); + + //Update the display status for the selected device. + sender.SetDisplayStatus(args.Device, "Disconnected", DevicePickerDisplayStatusOptions.None); + rootPage.NotifyUser("Disconnected", NotifyType.StatusMessage); + + // Set the active device variables to null + activeDevice = null; + }); + } + + private async void Pvb_ProjectionStopping(object sender, EventArgs e) + { + ProjectionViewBroker broker = sender as ProjectionViewBroker; + + TimeSpan position = broker.ProjectedPage.Player.Position; + Uri source = broker.ProjectedPage.Player.Source; + + await rootPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Resuming playback on the first screen", NotifyType.StatusMessage); + this.player.Source = source; + + this.player.Position = position; + this.player.Play(); + rootPage.ProjectionViewPageControl = null; + }); + } + + #region MediaElement Status Methods + private void Player_CurrentStateChanged(object sender, RoutedEventArgs e) + { + // Update status + rootPage.NotifyUser(string.Format("{0} '{1}'", this.player.CurrentState, video.Title), NotifyType.StatusMessage); + } + private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Failed to load '{0}'", video.Title), NotifyType.ErrorMessage); + } + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Openend '{0}'", video.Title), NotifyType.StatusMessage); + + player.Play(); + } + + #endregion + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + } +} diff --git a/Samples/AdvancedCasting/cs/06_Combine_Casting_Tech.xaml b/Samples/AdvancedCasting/cs/06_Combine_Casting_Tech.xaml new file mode 100644 index 0000000000..eaebb49a1a --- /dev/null +++ b/Samples/AdvancedCasting/cs/06_Combine_Casting_Tech.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/06_Combine_Casting_Tech.xaml.cs b/Samples/AdvancedCasting/cs/06_Combine_Casting_Tech.xaml.cs new file mode 100644 index 0000000000..82df56d4a8 --- /dev/null +++ b/Samples/AdvancedCasting/cs/06_Combine_Casting_Tech.xaml.cs @@ -0,0 +1,575 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using Windows.UI.Xaml.Media; +using Windows.Media.DialProtocol; +using ScreenCasting.Data.Azure; +using ScreenCasting.Data.Common; +using Windows.Devices.Enumeration; +using System.Threading.Tasks; +using Windows.Media.Casting; +using ScreenCasting.Controls; +using ScreenCasting.Util; +using Windows.UI.ViewManagement; +using Windows.ApplicationModel.Core; +using Windows.UI.Core; +using Windows.Storage; + +namespace ScreenCasting +{ + public sealed partial class Scenario06 : Page + { + private const int MAX_RESULTS = 10; + + private MainPage rootPage; + private DevicePicker picker = null; + private DeviceInformation activeDevice = null; + private object activeCastConnectionHandler = null; + private VideoMetaData video = null; + int thisViewId; + + public Scenario06() + { + this.InitializeComponent(); + + rootPage = MainPage.Current; + + //Subscribe to player events + player.MediaOpened += Player_MediaOpened; + player.MediaFailed += Player_MediaFailed; + player.CurrentStateChanged += Player_CurrentStateChanged; + + // Get an Azure hosted video + AzureDataProvider dataProvider = new AzureDataProvider(); + video = dataProvider.GetRandomVideo(); + + //Set the source on the player + rootPage.NotifyUser(string.Format("Opening '{0}'", video.Title), NotifyType.StatusMessage); + this.player.Source = video.VideoLink; + this.LicenseText.Text = "License: " + video.License; + + //Configure the DIAL launch arguments for the current video + this.dial_launch_args_textbox.Text = string.Format("v={0}&t=0&pairingCode=E4A8136D-BCD3-45F4-8E49-AE01E9A46B5F", video.Id); + + //Subscribe for the clicked event on the custom cast button + ((MediaTransportControlsWithCustomCastButton)this.player.TransportControls).CastButtonClicked += TransportControls_CastButtonClicked; + + // Instantiate the Device Picker + picker = new DevicePicker(); + + //Hook up device selected event + picker.DeviceSelected += Picker_DeviceSelected; + + //Hook up device disconnected event + picker.DisconnectButtonClicked += Picker_DisconnectButtonClicked; + + //Hook up device disconnected event + picker.DevicePickerDismissed += Picker_DevicePickerDismissed; + + //Add the DIAL Filter, so that the application only shows DIAL devices that have the application installed or advertise that they can install them. + //BUG: picker.Filter.SupportedDeviceSelectors.Add(DialDevice.GetDeviceSelector(this.dial_appname_textbox.Text)); + picker.Filter.SupportedDeviceSelectors.Add("System.Devices.DevObjectType:=6 AND System.Devices.AepContainer.ProtocolIds:~~{0E261DE4-12F0-46E6-91BA-428607CCEF64} AND System.Devices.AepContainer.Categories:~~Multimedia.ApplicationLauncher.DIAL"); + + //Add the CAST API Filter, so that the application only shows Miracast, Bluetooth, DLNA devices that can render the video + // BUG: picker.Filter.SupportedDeviceSelectors.Add(await CastingDevice.GetDeviceSelectorFromCastingSourceAsync(player.GetAsCastingSource())); + // BUG: picker.Filter.SupportedDeviceSelectors.Add(CastingDevice.GetDeviceSelector(CastingPlaybackTypes.Video)); + picker.Filter.SupportedDeviceSelectors.Add("System.Devices.InterfaceClassGuid:=\"{D0875FB4-2196-4c7a-A63D-E416ADDD60A1}\"" + " AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True"); + + //Add projection manager filter + picker.Filter.SupportedDeviceSelectors.Add(ProjectionManager.GetDeviceSelector()); + + pvb.ProjectionStopping += Pvb_ProjectionStopping; + } + + ProjectionViewBroker pvb = new ProjectionViewBroker(); + + private void TransportControls_CastButtonClicked(object sender, EventArgs e) + { + //Pause Current Playback + player.Pause(); + + rootPage.NotifyUser("Show Device Picker Button Clicked", NotifyType.StatusMessage); + + //Get the custom transport controls + MediaTransportControlsWithCustomCastButton mtc = (MediaTransportControlsWithCustomCastButton)this.player.TransportControls; + //Retrieve the location of the casting button + GeneralTransform transform = mtc.CastButton.TransformToVisual(Window.Current.Content as UIElement); + Point pt = transform.TransformPoint(new Point(0, 0)); + + //Show the picker above our Show Device Picker button + picker.Show(new Rect(pt.X, pt.Y, mtc.CastButton.ActualWidth, mtc.CastButton.ActualHeight), Windows.UI.Popups.Placement.Above); + } + + #region Windows.Devices.Enumeration.DevicePicker Methods + private async void Picker_DeviceSelected(DevicePicker sender, DeviceSelectedEventArgs args) + { + string deviceId = args.SelectedDevice.Id; + + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + //Update the display status for the selected device to connecting. + try { picker.SetDisplayStatus(args.SelectedDevice, "Connecting", DevicePickerDisplayStatusOptions.ShowProgress); } catch { } + + //The selectedDeviceInfo instance is needed to be able to update the picker. + DeviceInformation selectedDeviceInfo = args.SelectedDevice; +#if DEBUG + // The args.SelectedCastingDevice is proxied from the picker process. The picker process is + // dismissmed as soon as you break into the debugger. Creating a non-proxied version + // allows debugging since the proxied version stops working once the picker is dismissed. + selectedDeviceInfo = await DeviceInformation.CreateFromIdAsync(args.SelectedDevice.Id); +#endif + + bool castSucceeded = false; + + // If the ProjectionManager API did not work and the device id will have 'dial' in it. + castSucceeded = await TryLaunchDialAppAsync(selectedDeviceInfo); + + // If it doesn't try the ProjectionManager API. + if (!castSucceeded) + castSucceeded = await TryProjectionManagerCastAsync(selectedDeviceInfo); + + //If DIAL and ProjectionManager did not work for the selected device, try the CAST API + if (!castSucceeded) + castSucceeded = await TryCastMediaElementAsync(selectedDeviceInfo); + + if (castSucceeded) + { + //Update the display status for the selected device. Try Catch in case the picker is not visible anymore. + try { picker.SetDisplayStatus(selectedDeviceInfo, "Connected", DevicePickerDisplayStatusOptions.ShowDisconnectButton); } catch { } + + // Hide the picker now that all the work is completed. Try Catch in case the picker is not visible anymore. + try { picker.Hide(); } catch { } + } + else + { + //Show a retry button when connecting to the selected device failed. + try { picker.SetDisplayStatus(selectedDeviceInfo, "Connecting failed", DevicePickerDisplayStatusOptions.ShowRetryButton); } catch { } + } + }); + } + private async void Picker_DevicePickerDismissed(DevicePicker sender, object args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + if (activeDevice == null) + { + player.Play(); + } + }); + } + private async void Picker_DisconnectButtonClicked(DevicePicker sender, DeviceDisconnectButtonClickedEventArgs args) + { + //Casting must occur from the UI thread. This dispatches the casting calls to the UI thread. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + rootPage.NotifyUser("Disconnect Button clicked", NotifyType.StatusMessage); + + //Update the display status for the selected device. + sender.SetDisplayStatus(args.Device, "Disconnecting", DevicePickerDisplayStatusOptions.ShowProgress); + + bool disconnected = false; + if (this.activeCastConnectionHandler is ProjectionViewBroker) + disconnected = TryStopProjectionManagerAsync((ProjectionViewBroker)activeCastConnectionHandler); + if (this.activeCastConnectionHandler is DialApp) + disconnected = await TryStopDialAppAsync((DialApp)activeCastConnectionHandler); + if (this.activeCastConnectionHandler is CastingConnection) + disconnected = await TryDisconnectCastingSessionAsync((CastingConnection)activeCastConnectionHandler); + + if (disconnected) + { + //Update the display status for the selected device. + try { sender.SetDisplayStatus(args.Device, "Disconnected", DevicePickerDisplayStatusOptions.None); } catch { } + // Set the active device variables to null + activeDevice = null; + activeCastConnectionHandler = null; + + //Hide the picker + sender.Hide(); + } + else + { + //Update the display status for the selected device. + sender.SetDisplayStatus(args.Device, "Disconnect failed", DevicePickerDisplayStatusOptions.ShowDisconnectButton); + } + }); + } + + #endregion + + #region ProjectionManager APIs + private async Task TryProjectionManagerCastAsync(DeviceInformation device) + { + bool projectionManagerCastAsyncSucceeded = false; + + if ((activeDevice ==null && ProjectionManager.ProjectionDisplayAvailable && device == null) || device != null) + { + thisViewId = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Id; + + // If projection is already in progress, then it could be shown on the monitor again + // Otherwise, we need to create a new view to show the presentation + if (rootPage.ProjectionViewPageControl == null) + { + // First, create a new, blank view + var thisDispatcher = Window.Current.Dispatcher; + await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + // ViewLifetimeControl is a wrapper to make sure the view is closed only + // when the app is done with it + rootPage.ProjectionViewPageControl = ViewLifetimeControl.CreateForCurrentView(); + + // Assemble some data necessary for the new page + pvb.MainPageDispatcher = thisDispatcher; + pvb.ProjectionViewPageControl = rootPage.ProjectionViewPageControl; + pvb.MainViewId = thisViewId; + + // Display the page in the view. Note that the view will not become visible + // until "StartProjectingAsync" is called + var rootFrame = new Frame(); + rootFrame.Navigate(typeof(ProjectionViewPage), pvb); + Window.Current.Content = rootFrame; + Window.Current.Activate(); + }); + } + + try + { + // Start/StopViewInUse are used to signal that the app is interacting with the + // view, so it shouldn't be closed yet, even if the user loses access to it + rootPage.ProjectionViewPageControl.StartViewInUse(); + + try + { + rootPage.NotifyUser(string.Format("Starting projection of '{0}' on a second view '{1}' using ProjectionManager", video.Title, device.Name), NotifyType.StatusMessage); + + await ProjectionManager.StartProjectingAsync(rootPage.ProjectionViewPageControl.Id, thisViewId, device); + } + catch (Exception ex) + { + if (!ProjectionManager.ProjectionDisplayAvailable) + throw ex; + } + + if (pvb.ProjectedPage != null) + { + this.player.Pause(); + await pvb.ProjectedPage.SetMediaSource(this.player.Source, this.player.Position); + } + if (device != null) + { + activeDevice = device; + activeCastConnectionHandler = pvb; + } + projectionManagerCastAsyncSucceeded = true; + + rootPage.NotifyUser(string.Format("Displaying '{0}' on a second view '{1}' using ProjectionManager", video.Title, device.Name), NotifyType.StatusMessage); + } + catch (Exception) + { + rootPage.NotifyUser("The projection view is being disposed", NotifyType.ErrorMessage); + } + ApplicationView.GetForCurrentView().ExitFullScreenMode(); + } + return projectionManagerCastAsyncSucceeded; + } + private bool TryStopProjectionManagerAsync(ProjectionViewBroker broker) + { + broker.ProjectedPage.StopProjecting(); + return true; + } + + + private async void Pvb_ProjectionStopping(object sender, EventArgs e) + { + ProjectionViewBroker broker = sender as ProjectionViewBroker; + + TimeSpan position = broker.ProjectedPage.Player.Position; + Uri source = broker.ProjectedPage.Player.Source; + + await rootPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Resuming playback on the first screen", NotifyType.StatusMessage); + this.player.Source = source; + this.player.Position = position; + this.player.Play(); + rootPage.ProjectionViewPageControl = null; + }); + } + + #endregion + + #region Windows.Media.Casting APIs + + private async Task TryCastMediaElementAsync(DeviceInformation device) + { + bool castMediaElementSucceeded = false; + + //Verify whether the selected device supports DLNA, Bluetooth, or Miracast. + rootPage.NotifyUser(string.Format("Checking to see if device {0} supports Miracast, Bluetooth, or DLNA", device.Name), NotifyType.StatusMessage); + + CastingConnection connection = null; + + //Check to see whether we are casting to the same device + if (activeDevice != null && device.Id == activeDevice.Id) + connection = activeCastConnectionHandler as CastingConnection; + else // if not casting to the same device reset the active device related variables. + { + activeDevice = null; + activeCastConnectionHandler = null; + } + + // If we can re-use the existing connection + if (connection == null || connection.State == CastingConnectionState.Disconnected || connection.State == CastingConnectionState.Disconnecting) + { + CastingDevice castDevice = null; + activeDevice = null; + + //Try to create a CastingDevice instannce. If it doesn't succeed, the selected device does not support playback of the video source. + rootPage.NotifyUser(string.Format("Attempting to resolve casting device for '{0}'", device.Name), NotifyType.StatusMessage); + try { castDevice = await CastingDevice.FromIdAsync(device.Id); } catch { } + + if (castDevice == null) + { + //Try to create a DIAL device. If it doesn't succeed, the selected device does not support DIAL. + rootPage.NotifyUser(string.Format("'{0}' does not support playback of this media", device.Name), NotifyType.StatusMessage); + } + else + { + //Create a casting conneciton from our selected casting device + rootPage.NotifyUser(string.Format("Creating connection for '{0}'", device.Name), NotifyType.StatusMessage); + connection = castDevice.CreateCastingConnection(); + + //Hook up the casting events + connection.ErrorOccurred += Connection_ErrorOccurred; + connection.StateChanged += Connection_StateChanged; + } + + //Cast the content loaded in the media element to the selected casting device + rootPage.NotifyUser(string.Format("Casting to '{0}'", device.Name), NotifyType.StatusMessage); + + CastingSource source = null; + // Get the casting source + try { source = player.GetAsCastingSource(); } catch { } + + if (source == null) + { + rootPage.NotifyUser(string.Format("Failed to get casting source for video '{0}'", video.Title), NotifyType.ErrorMessage); + } + else + { + CastingConnectionErrorStatus status = await connection.RequestStartCastingAsync(source); + + if (status == CastingConnectionErrorStatus.Succeeded) + { + //Remember the device to which casting succeeded + activeDevice = device; + //Remember the current active connection. + activeCastConnectionHandler = connection; + castMediaElementSucceeded = true; + player.Play(); + } + else + { + rootPage.NotifyUser(string.Format("Failed to cast to '{0}'", device.Name), NotifyType.ErrorMessage); + } + } + } + return castMediaElementSucceeded; + } + private async void Connection_StateChanged(CastingConnection sender, object args) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Casting Connection State Changed: " + sender.State, NotifyType.StatusMessage); + }); + } + private async void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + rootPage.NotifyUser("Casting Error Occured: " + args.Message, NotifyType.ErrorMessage); + activeDevice = null; + activeCastConnectionHandler = null; + }); + } + private async Task TryDisconnectCastingSessionAsync(CastingConnection connection) + { + bool disconnected = false; + + //Disconnect the casting session + CastingConnectionErrorStatus status = await connection.DisconnectAsync(); + + if (status == CastingConnectionErrorStatus.Succeeded) + { + rootPage.NotifyUser("Connection disconnected successfully.", NotifyType.StatusMessage); + disconnected = true; + } + else + { + rootPage.NotifyUser(string.Format("Failed to disconnect connection with reason {0}.", status.ToString()), NotifyType.ErrorMessage); + } + + return disconnected; + } + + #endregion + + #region Windows.Media.DialProtocol APIs + private async Task TryLaunchDialAppAsync(DeviceInformation device) + { + bool dialAppLaunchSucceeded = false; + + //Update the launch arguments to include the Position + this.dial_launch_args_textbox.Text = string.Format("v={0}&t={1}&pairingCode=E4A8136D-BCD3-45F4-8E49-AE01E9A46B5F", video.Id, player.Position.Ticks); + + //Try to create a DIAL device. If it doesn't succeed, the selected device does not support DIAL. + rootPage.NotifyUser(string.Format("Checking to see if device {0} supports DIAL", device.Name), NotifyType.StatusMessage); + + DialDevice dialDevice = null; + + //Try to create a DIAL device. If it doesn't succeed, the selected device does not support DIAL. + rootPage.NotifyUser(string.Format("Attempting to resolve DIAL device for '{0}'", device.Name), NotifyType.StatusMessage); + + string[] newIds = (string[])device.Properties["{0BBA1EDE-7566-4F47-90EC-25FC567CED2A} 2"]; + + if (newIds.Length > 0) + { + string deviceId = newIds[0]; + try { dialDevice = await DialDevice.FromIdAsync(deviceId); } catch { } + } + + if (dialDevice == null) + { + //Try to create a DIAL device. If it doesn't succeed, the selected device does not support DIAL. + rootPage.NotifyUser(string.Format("'{0}' does not support DIAL", device.Name), NotifyType.StatusMessage); + } + else + { + //Get the DialApp object for the specific application on the selected device + DialApp app = dialDevice.GetDialApp(this.dial_appname_textbox.Text); + + if (app == null) + { + //Try to create a DIAL device. If it doesn't succeed, the selected device does not support DIAL. + rootPage.NotifyUser(string.Format("'{0}' cannot find app with ID '{1}'", device.Name, this.dial_appname_textbox.Text), NotifyType.StatusMessage); + } + else + { + rootPage.NotifyUser(string.Format("Attempting to launch '{0}'", app.AppName), NotifyType.StatusMessage); + //Launch the application on the 1st screen device + DialAppLaunchResult result = await app.RequestLaunchAsync(this.dial_launch_args_textbox.Text); + + //Verify to see whether the application was launched + if (result == DialAppLaunchResult.Launched) + { + //Remember the device to which casting succeeded + activeDevice = device; + //DIAL is sessionsless but the DIAL app allows us to get the state and "disconnect". + //Disconnect in the case of DIAL is equivalenet to stopping the app. + activeCastConnectionHandler = app; + rootPage.NotifyUser(string.Format("Launched '{0}'", app.AppName), NotifyType.StatusMessage); + //This is where you will need to add you application specific communication between your 1st and 2nd screen applications + //... + + + dialAppLaunchSucceeded = true; + } + } + } + + return dialAppLaunchSucceeded; + } + private async Task TryStopDialAppAsync(DialApp app) + { + bool stopped = false; + + //Get the current application state + DialAppStateDetails stateDetails = await app.GetAppStateAsync(); + + switch (stateDetails.State) + { + case DialAppState.NetworkFailure: + { + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser("Network Failure while getting application state", NotifyType.ErrorMessage); + break; + } + case DialAppState.Stopped: + { + stopped = true; + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser("Application was already stopped.", NotifyType.StatusMessage); + break; + } + default: + { + DialAppStopResult result = await app.StopAsync(); + + if (result == DialAppStopResult.Stopped) + { + stopped = true; + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser("Application stopped successfully.", NotifyType.StatusMessage); + } + else + { + if (result == DialAppStopResult.StopFailed || result == DialAppStopResult.NetworkFailure) + { + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser(string.Format("Error occured trying to stop application. Status: '{0}'", result.ToString()), NotifyType.StatusMessage); + } + else //in case of DialAppStopResult.OperationNotSupported, there is not much more you can do. You could implement your own + // mechanism to stop the application on that device. + { + stopped = true; + // In case getting the application state failed because of a network failure, you could add retry logic + rootPage.NotifyUser(string.Format("Stop is not supported by device: '{0}'", activeDevice.Name), NotifyType.ErrorMessage); + } + } + break; + } + } + return stopped; + } + + #endregion + + #region Media Element Status Methods + private void Player_CurrentStateChanged(object sender, RoutedEventArgs e) + { + // Update status + rootPage.NotifyUser(string.Format("{0} '{1}'", this.player.CurrentState, video.Title), NotifyType.StatusMessage); + } + private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Failed to load '{0}'", video.Title), NotifyType.ErrorMessage); + } + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + rootPage.NotifyUser(string.Format("Openend '{0}'", video.Title), NotifyType.StatusMessage); + + player.Play(); + } + + #endregion + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + } +} diff --git a/Samples/AdvancedCasting/cs/AdvancedCasting.csproj b/Samples/AdvancedCasting/cs/AdvancedCasting.csproj new file mode 100644 index 0000000000..3e1a571ecd --- /dev/null +++ b/Samples/AdvancedCasting/cs/AdvancedCasting.csproj @@ -0,0 +1,232 @@ + + + + + Debug + x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F} + AppContainerExe + Properties + ScreenCasting + ScreenCasting + en-US + UAP + 10.0.10240.0 + 10.0.10240.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + 02_Casting_API_CastButton.xaml + + + 03_DIAL_Sender_API.xaml + + + 05_Multi_View_Media_Application.xaml + + + 06_Combine_Casting_Tech.xaml + + + + UnhandledExceptionPage.xaml + + + App.xaml + + + + + + + + + MainPage.xaml + + + ProjectionViewPage.xaml + + + + + 01_MediaElement.xaml + + + 04_DIAL_Receiver_App.xaml + + + + + + + + + Designer + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Styles\Styles.xaml + MSBuild:Compile + Designer + + + + + Properties\Default.rd.xml + + + Assets\casting.mp4 + + + Assets\smallTile-sdk.png + + + Assets\splash-sdk.png + + + Assets\squareTile-sdk.png + + + Assets\storeLogo-sdk.png + + + Assets\tile-sdk.png + + + + 14.0 + + + + \ No newline at end of file diff --git a/Samples/AdvancedCasting/cs/AdvancedCasting.sln b/Samples/AdvancedCasting/cs/AdvancedCasting.sln new file mode 100644 index 0000000000..b3a186300f --- /dev/null +++ b/Samples/AdvancedCasting/cs/AdvancedCasting.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedCasting", "AdvancedCasting.csproj", "{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}" +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 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.ActiveCfg = Debug|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.Build.0 = Debug|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.Deploy.0 = Debug|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.ActiveCfg = Debug|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.Build.0 = Debug|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.Deploy.0 = Debug|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.ActiveCfg = Debug|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.Build.0 = Debug|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.Deploy.0 = Debug|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.ActiveCfg = Release|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.Build.0 = Release|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.Deploy.0 = Release|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.ActiveCfg = Release|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.Build.0 = Release|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.Deploy.0 = Release|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.ActiveCfg = Release|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.Build.0 = Release|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/AdvancedCasting/cs/App.xaml b/Samples/AdvancedCasting/cs/App.xaml new file mode 100644 index 0000000000..3546dae999 --- /dev/null +++ b/Samples/AdvancedCasting/cs/App.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/App.xaml.cs b/Samples/AdvancedCasting/cs/App.xaml.cs new file mode 100644 index 0000000000..cb79a52d21 --- /dev/null +++ b/Samples/AdvancedCasting/cs/App.xaml.cs @@ -0,0 +1,166 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=402347&clcid=0x409 + +namespace ScreenCasting +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + this.Suspending += OnSuspending; + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { +#if DEBUG + if (System.Diagnostics.Debugger.IsAttached) + { + this.DebugSettings.EnableFrameRateCounter = false; + + } + +#endif + Application.Current.UnhandledException += Current_UnhandledException; + + Window.Current.Activate(); + + Frame rootFrame = Window.Current.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + // Set the default language + rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0]; + + rootFrame.NavigationFailed += OnNavigationFailed; + + if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) + { + //TODO: Load state from previously suspended application + } + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + Window.Current.Activate(); + } + + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + try + { + rootFrame.Navigate(typeof(MainPage), e); + } + catch (Exception ex) + { + Window.Current.Content = new Frame(); + Window.Current.Activate(); + rootFrame.Navigate(typeof(UnhandledExceptionPage), e.Arguments); + ((UnhandledExceptionPage)rootFrame.Content).StatusMessage = ex.Message + ex.StackTrace; + } + + } + + + // Ensure the current window is active + Window.Current.Activate(); + } + + private void Current_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Window.Current.Content = new Frame(); + Frame rootFrame = Window.Current.Content as Frame; + Window.Current.Activate(); + rootFrame.Navigate(typeof(UnhandledExceptionPage)); + ((UnhandledExceptionPage)rootFrame.Content).StatusMessage = e.Exception.Message + e.Exception.StackTrace; + } + + protected override void OnActivated(IActivatedEventArgs args) + { + try + { + Window.Current.Content = new Frame(); + Frame rootFrame = Window.Current.Content as Frame; + Window.Current.Activate(); + + + if (args.Kind == ActivationKind.DialReceiver) + { + rootFrame.Navigate(typeof(MainPage), args); + } + else + { + rootFrame.Navigate(typeof(MainPage)); + } + base.OnActivated(args); + } + catch (Exception ex) + { + Window.Current.Content = new Frame(); + Frame rootFrame = Window.Current.Content as Frame; + Window.Current.Activate(); + rootFrame.Navigate(typeof(UnhandledExceptionPage)); + ((UnhandledExceptionPage)rootFrame.Content).StatusMessage = ex.Message + ex.StackTrace; + } + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + //TODO: Save application state and stop any background activity + deferral.Complete(); + } + } +} diff --git a/Samples/AdvancedCasting/cs/Controls/MediaTransportControlsWithCustomCastButton.cs b/Samples/AdvancedCasting/cs/Controls/MediaTransportControlsWithCustomCastButton.cs new file mode 100644 index 0000000000..8a66777aab --- /dev/null +++ b/Samples/AdvancedCasting/cs/Controls/MediaTransportControlsWithCustomCastButton.cs @@ -0,0 +1,55 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Documents; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace ScreenCasting.Controls +{ + public sealed class MediaTransportControlsWithCustomCastButton : MediaTransportControls + { + + public MediaTransportControlsWithCustomCastButton() + { + this.DefaultStyleKey = typeof(MediaTransportControlsWithCustomCastButton); + } + + public event EventHandler CastButtonClicked; + private void CastButton_Click(object sender, RoutedEventArgs e) + { + if (CastButtonClicked != null) + CastButtonClicked(this, EventArgs.Empty); + } + + public Button CastButton + { + get { return this.GetTemplateChild("CustomCastButton") as Button; } + } + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + this.IsCompact = true; + + CastButton.Click += CastButton_Click; + } + } +} diff --git a/Samples/AdvancedCasting/cs/Controls/ProjectedMediaTransportControls.cs b/Samples/AdvancedCasting/cs/Controls/ProjectedMediaTransportControls.cs new file mode 100644 index 0000000000..803042b4e5 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Controls/ProjectedMediaTransportControls.cs @@ -0,0 +1,65 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Documents; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace ScreenCasting.Controls +{ + public sealed class ProjectedMediaTransportControls : MediaTransportControls + { + + public ProjectedMediaTransportControls() + { + this.DefaultStyleKey = typeof(ProjectedMediaTransportControls); + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + //Find the Swap Views button and subscribe to the clicked event. + Button swapViewsButton = GetTemplateChild("SwapViewsButton") as Button; + swapViewsButton.Click += SwapViewsButton_Click; + + //Find the Stop Projecting button and subscribe to the clicked event. + Button stopProjectingButton = GetTemplateChild("StopProjectingButton") as Button; + stopProjectingButton.Click += StopProjectingButton_Click; + + this.IsCompact = true; + } + + public event EventHandler StopProjectingButtonClick; + public event EventHandler SwapViewsButtonClick; + + private void StopProjectingButton_Click (object sender, RoutedEventArgs e) + { + if (StopProjectingButtonClick != null) + StopProjectingButtonClick(this, EventArgs.Empty); + } + + private void SwapViewsButton_Click(object sender, RoutedEventArgs e) + { + if (SwapViewsButtonClick != null) + SwapViewsButtonClick(this, EventArgs.Empty); + } + } +} diff --git a/Samples/AdvancedCasting/cs/Controls/ProjectionViewBroker.cs b/Samples/AdvancedCasting/cs/Controls/ProjectionViewBroker.cs new file mode 100644 index 0000000000..f4a39c81f4 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Controls/ProjectionViewBroker.cs @@ -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. +// +//********************************************************* + +using ScreenCasting.Controls; +using ScreenCasting.Util; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Core; +using Windows.UI.Xaml.Controls; + +namespace ScreenCasting +{ + // This is a simple container for a set of data used to comminicate between the main and the projection view + internal class ProjectionViewBroker + { + public CoreDispatcher MainPageDispatcher; + public ViewLifetimeControl ProjectionViewPageControl; + public int MainViewId; + public event EventHandler ProjectionStopping; + public ProjectionViewPage ProjectedPage; + public void NotifyProjectionStopping() + { + try + { + if (ProjectionStopping != null) + ProjectionStopping(this, EventArgs.Empty); + } + catch { } + } + + } +} diff --git a/Samples/AdvancedCasting/cs/Data/Azure/AzureDataProvider.cs b/Samples/AdvancedCasting/cs/Data/Azure/AzureDataProvider.cs new file mode 100644 index 0000000000..c669944b0d --- /dev/null +++ b/Samples/AdvancedCasting/cs/Data/Azure/AzureDataProvider.cs @@ -0,0 +1,106 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Web.Syndication; +using ScreenCasting.Data.Common; + +namespace ScreenCasting.Data.Azure +{ + public class AzureDataProvider : ItemsDataProvider + { + private static Dictionary s_metaDataList = null; + private const int MAX_RESULTS = 10; + public override VideoMetaData GetRandomVideo () + { + List videos = GetAll(MAX_RESULTS); + Random indexRandomizer = new Random(); + + // Pick a random video + return videos[indexRandomizer.Next(0, videos.Count - 1)]; + } + public override List GetAll(int max_results) + { + if (s_metaDataList == null) + { + Dictionary l = new Dictionary(); + + VideoMetaData video1 = new VideoMetaData(); + video1.Id = "AzureMediaServicesOverview"; + video1.PubDate = DateTime.Now; + video1.VideoLink = new Uri("http://amssamples.streaming.mediaservices.windows.net/91492735-c523-432b-ba01-faba6c2206a2/AzureMediaServicesPromo.ism/manifest(format=m3u8-aapl)"); + video1.Title = "Azure Media Services Overview"; + video1.WebPageLink = new Uri("http://amsplayer.azurewebsites.net/amssamples.html"); + video1.License = "(C) Microsoft Coorporation | All Rights Reserved"; + video1.Thumbnail = new Uri("http://t3.gstatic.com/images?q=tbn:ANd9GcRoTu81vs8GuQtJBGUZ0pLEiNHVVx3dFwHsu7JCkvGop8Z-98EsPg"); + l.Add(video1.Id, video1); + + VideoMetaData video2 = new VideoMetaData(); + video2.Id = "BigBuckBunnyTrailer"; + video2.PubDate = DateTime.Now; + video2.VideoLink = new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi"); + video2.Title = "Big Buck Bunny"; + video2.WebPageLink = new Uri("https://peach.blender.org/"); + video2.License = "(CC) Blender Foundation | peach.blender.org"; + video2.Thumbnail = new Uri("http://t0.gstatic.com/images?q=tbn:ANd9GcQT54UKh0zX5OUDNLRyXOOwt3pqj0lpaLCJebucva2LSV49aGjRfg"); + l.Add(video2.Id, video2); + + VideoMetaData video3 = new VideoMetaData(); + video3.Id = "bc57e088-27ec-44e0-ac20-a85ccbcd50da"; + video3.PubDate = DateTime.Now; + video3.VideoLink = new Uri("http://amssamples.streaming.mediaservices.windows.net/bc57e088-27ec-44e0-ac20-a85ccbcd50da/TearsOfSteel.ism/manifest(format=mpd-time-csf)"); + video3.Title = "Tears of Steel"; + video3.WebPageLink = new Uri("https://mango.blender.org/"); + video3.License = "(CC) Blender Foundation | durian.blender.org/"; + video3.Thumbnail = new Uri("http://t3.gstatic.com/images?q=tbn:ANd9GcQO0MMO_vXf8Q1zjZWLHa1_566Mf_jty6vJKRi9R-C_0W-gXnNOog"); + l.Add(video3.Id, video3); + + //VideoMetaData video4 = new VideoMetaData(); + //video4.Id = "b6822ec8-5c2b-4ae0-a851-fd46a78294e9"; + //video4.PubDate = DateTime.Now; + //video4.VideoLink = new Uri("http://amssamples.streaming.mediaservices.windows.net/b6822ec8-5c2b-4ae0-a851-fd46a78294e9/ElephantsDream.ism/manifest(filtername=FirstFilter,format=mpd-time-csf)"); + //video4.Title = "Elephants Dream"; + //video4.WebPageLink = new Uri("https://orange.blender.org/"); + //video4.License = "(c) copyright 2006, Blender Foundation / Netherlands Media Art Institute / www.elephantsdream.org"; + //video4.Thumbnail = new Uri("https://orange.blender.org/wp-content/uploads/2006/05/edscore_cover_l.jpg"); + //l.Add(video4.Id, video4); + + + VideoMetaData video5 = new VideoMetaData(); + video5.Id = "49b57c87-f5f3-48b3-ba22-c55cfdffa9cb"; + video5.PubDate = DateTime.Now; + video5.VideoLink = new Uri("http://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=m3u8-aapl)"); + video5.Title = "Sintel"; + video5.WebPageLink = new Uri("https://durian.blender.org/"); + video5.License = "© copyright Blender Foundation | www.sintel.org"; + video5.Thumbnail = new Uri("https://durian.blender.org/wp-content/uploads/2010/05/sintel_trailer_1080.jpg"); + l.Add(video5.Id, video5); + s_metaDataList = l; + } + return s_metaDataList.Values.ToList(); + } + + public override VideoMetaData GetFromID(string id) + { + if (s_metaDataList == null) + GetAll(20); + + VideoMetaData video = s_metaDataList[id]; + + return video; + } + + } +} diff --git a/Samples/AdvancedCasting/cs/Data/Common/ItemsDataProvider.cs b/Samples/AdvancedCasting/cs/Data/Common/ItemsDataProvider.cs new file mode 100644 index 0000000000..e26313b534 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Data/Common/ItemsDataProvider.cs @@ -0,0 +1,28 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScreenCasting.Data.Common +{ + public abstract class ItemsDataProvider + { + public abstract List GetAll(int max_results); + + public abstract VideoMetaData GetRandomVideo(); + public abstract VideoMetaData GetFromID(string ID); + + } +} diff --git a/Samples/AdvancedCasting/cs/Data/Common/VideoMetaData.cs b/Samples/AdvancedCasting/cs/Data/Common/VideoMetaData.cs new file mode 100644 index 0000000000..ae2629d0a6 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Data/Common/VideoMetaData.cs @@ -0,0 +1,30 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScreenCasting.Data.Common +{ + public class VideoMetaData + { + public string Id { get; set; } + public string Title { get; set; } + public DateTime PubDate { get; set; } + public string License { get; set; } + public Uri WebPageLink { get; set; } + public Uri VideoLink { get; set; } + public Uri Thumbnail { get; set; } + } +} diff --git a/Samples/AdvancedCasting/cs/MainPage.xaml b/Samples/AdvancedCasting/cs/MainPage.xaml new file mode 100644 index 0000000000..6de6a0fa33 --- /dev/null +++ b/Samples/AdvancedCasting/cs/MainPage.xaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Status: + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/MainPage.xaml.cs b/Samples/AdvancedCasting/cs/MainPage.xaml.cs new file mode 100644 index 0000000000..b3ae3f494a --- /dev/null +++ b/Samples/AdvancedCasting/cs/MainPage.xaml.cs @@ -0,0 +1,218 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Util; +using System; +using System.Collections.Generic; +using Windows.ApplicationModel.Activation; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 + +namespace ScreenCasting +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class MainPage : Page + { + public static MainPage Current; + public ViewLifetimeControl ProjectionViewPageControl; + public MainPage() + { + LoadScenarios(); + + this.DataContext = this; + + this.InitializeComponent(); + + // This is a static public property that allows downstream pages to get a handle to the MainPage instance + // in order to call methods that are in this class. + Current = this; + SampleTitle.Text = FEATURE_NAME; + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ApplicationView.GetForCurrentView().ExitFullScreenMode(); + this.ScenarioControl.SelectionChanged += ScenarioControl_SelectionChanged; + + try + { + // Populate the scenario list from the SampleConfiguration.cs file + ScenarioControl.ItemsSource = Scenarios; + + if (e.Parameter is DialReceiverActivatedEventArgs) + { + NavigateToScenario(typeof(Scenario04), e.Parameter); + } + else + { + ScenarioControl.SelectedIndex = 0; + } + + } + catch (Exception ex) + { + Window.Current.Content = new Frame(); + Frame rootFrame = Window.Current.Content as Frame; + rootFrame.Navigate(typeof(UnhandledExceptionPage), null); + ((UnhandledExceptionPage)rootFrame.Content).StatusMessage = ex.Message + ex.StackTrace; + } + } + + /// + /// Called whenever the user changes selection in the scenarios list. This method will navigate to the respective + /// sample scenario page. + /// + /// + /// + private void ScenarioControl_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + // Clear the status block when navigating scenarios. + NotifyUser(String.Empty, NotifyType.StatusMessage); + + ListBox scenarioListBox = sender as ListBox; + Scenario s = Scenarios[scenarioListBox.SelectedIndex]; + if (s != null) + { + ScenarioFrame.Navigate(s.ClassType); + if (Window.Current.Bounds.Width < 640) + { + Splitter.IsPaneOpen = false; + StatusBorder.Visibility = Visibility.Collapsed; + } + else + { + Splitter.IsPaneOpen = true; + StatusBorder.Visibility = Visibility.Visible; + } + } + } + + + + internal void NavigateToScenario(Type scenarioType, object args) + { + try + { + // Clear the status block when navigating scenarios. + NotifyUser(String.Empty, NotifyType.StatusMessage); + + ListBox scenarioListBox = this.ScenarioControl; + + int selectedIndex = -1; + + this.ScenarioControl.SelectionChanged -= ScenarioControl_SelectionChanged; + for (int idx = 0; idx < scenarioListBox.Items.Count; idx++) + { + if (((Scenario)scenarioListBox.Items[idx]).ClassType == scenarioType) + { + selectedIndex = idx; + break; + } + } + + if (selectedIndex > -1) + scenarioListBox.SelectedIndex = selectedIndex; + + Scenario s = scenarioListBox.SelectedItem as Scenario; + + if (s != null) + { + ScenarioFrame.Navigate(s.ClassType, args); + if (Window.Current.Bounds.Width < 640) + { + Splitter.IsPaneOpen = false; + StatusBorder.Visibility = Visibility.Collapsed; + } + else + { + Splitter.IsPaneOpen = true; + StatusBorder.Visibility = Visibility.Visible; + } + } + this.ScenarioControl.SelectionChanged += ScenarioControl_SelectionChanged; + } + catch(Exception ex) + { + Frame rootFrame = Window.Current.Content as Frame; + + Window.Current.Content = new Frame(); + rootFrame.Navigate(typeof(UnhandledExceptionPage), ex.Message); + ((UnhandledExceptionPage)rootFrame.Content).StatusMessage = ex.Message + ex.StackTrace; + } + } + + + public List Scenarios + { + get { return this.scenarios; } + } + + /// + /// Used to display messages to the user + /// + /// + /// + public void NotifyUser(string strMessage, NotifyType type) + { + switch (type) + { + case NotifyType.StatusMessage: + StatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Green); + break; + case NotifyType.ErrorMessage: + StatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Red); + break; + } + StatusBlock.Text = strMessage; + + // Collapse the StatusBlock if it has no text to conserve real estate. + StatusBorder.Visibility = (StatusBlock.Text != String.Empty) ? Visibility.Visible : Visibility.Collapsed; + } + + async void Footer_Click(object sender, RoutedEventArgs e) + { + await Windows.System.Launcher.LaunchUriAsync(new Uri(((HyperlinkButton)sender).Tag.ToString())); + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + Splitter.IsPaneOpen = (Splitter.IsPaneOpen == true) ? false : true; + StatusBorder.Visibility = Visibility.Collapsed; + } + } + public enum NotifyType + { + StatusMessage, + ErrorMessage + }; + + //public class ScenarioBindingConverter : IValueConverter + //{ + // public object Convert(object value, Type targetType, object parameter, string language) + // { + // Scenario s = value as Scenario; + // return (MainPage.Current.Scenarios.IndexOf(s) + 1) + ") " + s.Title; + // } + + // public object ConvertBack(object value, Type targetType, object parameter, string language) + // { + // return true; + // } + //} +} diff --git a/Samples/AdvancedCasting/cs/Package.appxmanifest b/Samples/AdvancedCasting/cs/Package.appxmanifest new file mode 100644 index 0000000000..57f90fd121 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Package.appxmanifest @@ -0,0 +1,37 @@ + + + + + + ScreenCasting C# Sample + Microsoft Corporation + Assets\StoreLogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AdvancedCasting/cs/ProjectionViewPage.xaml b/Samples/AdvancedCasting/cs/ProjectionViewPage.xaml new file mode 100644 index 0000000000..a8c8848000 --- /dev/null +++ b/Samples/AdvancedCasting/cs/ProjectionViewPage.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/ProjectionViewPage.xaml.cs b/Samples/AdvancedCasting/cs/ProjectionViewPage.xaml.cs new file mode 100644 index 0000000000..d5aaef8cd9 --- /dev/null +++ b/Samples/AdvancedCasting/cs/ProjectionViewPage.xaml.cs @@ -0,0 +1,142 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using ScreenCasting.Controls; +using System; +using System.Threading.Tasks; +using Windows.UI.Core; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace ScreenCasting +{ + public sealed partial class ProjectionViewPage : Page + { + public ProjectionViewPage() + { + this.InitializeComponent(); + + ProjectedMediaTransportControls pmtcs = this.player.TransportControls as ProjectedMediaTransportControls; + if (pmtcs != null) + pmtcs.StopProjectingButtonClick += ProjectionViewPage_StopProjectingButtonClick; + + this.player.MediaOpened += Player_MediaOpened; + } + + private void Player_MediaOpened(object sender, RoutedEventArgs e) + { + this.player.IsFullWindow = true; + this.player.AreTransportControlsEnabled = true; + } + + private void ProjectionViewPage_StopProjectingButtonClick(object sender, EventArgs e) + { + this.StopProjecting(); + } + + + + public async Task SetMediaSource (Uri source, TimeSpan position) + { + await this.player.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + this.player.Source = source; + this.player.Position = position; + this.player.Play(); + }); + return true; + } + + public MediaElement Player + { + get { return this.player; } + } + + ProjectionViewBroker broker = null; + protected override void OnNavigatedTo(NavigationEventArgs e) + { + broker = (ProjectionViewBroker)e.Parameter; + broker.ProjectedPage = this; + + // Listen for when it's time to close this view + broker.ProjectionViewPageControl.Released += thisViewControl_Released; + } + + private async void thisViewControl_Released(object sender, EventArgs e) + { + // There are two major cases where this event will get invoked: + // 1. The view goes unused for some time, and the system cleans it up + // 2. The app calls "StopProjectingAsync" + broker.ProjectionViewPageControl.Released -= thisViewControl_Released; + await broker.ProjectionViewPageControl.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + this.broker.NotifyProjectionStopping(); + MainPage.Current.ProjectionViewPageControl = null; + }); + + this.player.Stop(); + this.player.Source = null; + + Window.Current.Close(); + } + + public async void SwapViews() + { + // The view might arrive on the wrong display. The user can + // easily swap the display on which the view appears + broker.ProjectionViewPageControl.StartViewInUse(); + await ProjectionManager.SwapDisplaysForViewsAsync( + ApplicationView.GetForCurrentView().Id, + broker.MainViewId + ); + broker.ProjectionViewPageControl.StopViewInUse(); + } + private void SwapViews_Click(object sender, RoutedEventArgs e) + { + SwapViews(); + } + + public async void StopProjecting() + { + broker.NotifyProjectionStopping(); + + // There may be cases to end the projection from the projected view + // (e.g. the presentation hosted in that view concludes) + // broker.ProjectionViewPageControl.StartViewInUse(); + await this.player.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => + { + this.player.Stop(); + this.player.Source = null; + + broker.ProjectionViewPageControl.StartViewInUse(); + + try + { + await ProjectionManager.StopProjectingAsync( + broker.ProjectionViewPageControl.Id, + broker.MainViewId + ); + } + catch { } + Window.Current.Close(); + + }); + + broker.ProjectionViewPageControl.StopViewInUse(); + } + private void StopProjecting_Click(object sender, RoutedEventArgs e) + { + StopProjecting(); + } + } +} diff --git a/Samples/AdvancedCasting/cs/Properties/AssemblyInfo.cs b/Samples/AdvancedCasting/cs/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..8deb85e22b --- /dev/null +++ b/Samples/AdvancedCasting/cs/Properties/AssemblyInfo.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ScreenCasting")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ScreenCasting")] +[assembly: AssemblyCopyright("Copyright 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] diff --git a/Samples/AdvancedCasting/cs/SampleConfiguration.cs b/Samples/AdvancedCasting/cs/SampleConfiguration.cs new file mode 100644 index 0000000000..ed2b290844 --- /dev/null +++ b/Samples/AdvancedCasting/cs/SampleConfiguration.cs @@ -0,0 +1,55 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using Windows.UI.Xaml.Controls; +using ScreenCasting; +using System.Reflection; +using ScreenCasting.Util; + +namespace ScreenCasting +{ + public partial class MainPage : Page + { + public const string FEATURE_NAME = "ScreenCasting"; + private List scenarios; + + private void LoadScenarios() + { + if (ApiInformation.IsTypePresent("Windows.Devices.Enumeration.DevicePicker")) + { + scenarios = new List + { + new Scenario() { Title="1 - Media Element Casting 101", ClassType=Type.GetType("ScreenCasting.Scenario01",false)} + ,new Scenario() { Title="2 - Casting APIs and a Custom Cast Button", ClassType=Type.GetType("ScreenCasting.Scenario02",false)} + ,new Scenario() { Title="3 - DIAL Sender Universal Windows app", ClassType=Type.GetType("ScreenCasting.Scenario03",false)} + ,new Scenario() { Title="4 - DIAL Receiver Windows Universal app", ClassType=Type.GetType("ScreenCasting.Scenario04")} + ,new Scenario() { Title="5 - Multi-View Media Application", ClassType=Type.GetType("ScreenCasting.Scenario05")} + ,new Scenario() { Title="6 - Combine Casting Methods", ClassType=Type.GetType("ScreenCasting.Scenario06")} + + }; + } + else + { + scenarios = new List { + new Scenario() { Title="DIAL Receiver Windows Universal Application", ClassType=typeof(Scenario04)} + }; + } + } + } + + public class Scenario + { + public string Title { get; set; } + public Type ClassType { get; set; } + } +} \ No newline at end of file diff --git a/Samples/AdvancedCasting/cs/Styles/MediaTransportControlWithCustomCastButtonStyles.xaml b/Samples/AdvancedCasting/cs/Styles/MediaTransportControlWithCustomCastButtonStyles.xaml new file mode 100644 index 0000000000..ba78b25875 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Styles/MediaTransportControlWithCustomCastButtonStyles.xaml @@ -0,0 +1,706 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Visible + + + + + + + + + + + Visible + + + + + + + + + + + + + Visible + + + + + + + + + + + + + + + + + + + + Visible + + + + + + + + + + + + + + + + + Visible + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Collapsed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/Styles/ProjectedMediaTransportControlsStyles.xaml b/Samples/AdvancedCasting/cs/Styles/ProjectedMediaTransportControlsStyles.xaml new file mode 100644 index 0000000000..854db0833a --- /dev/null +++ b/Samples/AdvancedCasting/cs/Styles/ProjectedMediaTransportControlsStyles.xaml @@ -0,0 +1,715 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Visible + + + + + + + + + + + Visible + + + + + + + + + + + + + Visible + + + + + + + + + + + + + + + + + + + + Visible + + + + + + + + + + + + + + + + + Visible + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Collapsed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/UnhandledExceptionPage.xaml b/Samples/AdvancedCasting/cs/UnhandledExceptionPage.xaml new file mode 100644 index 0000000000..ed4c4c39e2 --- /dev/null +++ b/Samples/AdvancedCasting/cs/UnhandledExceptionPage.xaml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/Samples/AdvancedCasting/cs/UnhandledExceptionPage.xaml.cs b/Samples/AdvancedCasting/cs/UnhandledExceptionPage.xaml.cs new file mode 100644 index 0000000000..4a3f80c847 --- /dev/null +++ b/Samples/AdvancedCasting/cs/UnhandledExceptionPage.xaml.cs @@ -0,0 +1,72 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 + +namespace ScreenCasting +{ + + + + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class UnhandledExceptionPage : Page + { + public static void ShowUnhandledException(Exception ex) + { + Frame rootFrame = Window.Current.Content as Frame; + if (rootFrame == null) + { + rootFrame = new Frame(); + Window.Current.Content = rootFrame; + Window.Current.Activate(); + } + + rootFrame.Navigate(typeof(UnhandledExceptionPage), ex.ToString()); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + + if(e.Parameter is string) + { + this.StatusMessage = (string)e.Parameter; + } + } + public UnhandledExceptionPage() + { + InitializeComponent(); + } + + public string StatusMessage + { + get { return this.Status.Text; } + set { this.Status.Text = value; } + } + } +} diff --git a/Samples/AdvancedCasting/cs/Util/ApiInformation.cs b/Samples/AdvancedCasting/cs/Util/ApiInformation.cs new file mode 100644 index 0000000000..391fda7ed5 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Util/ApiInformation.cs @@ -0,0 +1,35 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScreenCasting.Util +{ + class ApiInformation + { + public static bool IsTypePresent(string typeName) + { + try + { + Windows.Media.Casting.CastingDevicePicker picker = new Windows.Media.Casting.CastingDevicePicker(); + + return true; + } + catch { + return false; + } + } + } +} diff --git a/Samples/AdvancedCasting/cs/Util/CustomDevicePickerFilter.cs b/Samples/AdvancedCasting/cs/Util/CustomDevicePickerFilter.cs new file mode 100644 index 0000000000..c39acad575 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Util/CustomDevicePickerFilter.cs @@ -0,0 +1,45 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Devices.Enumeration; + +namespace ScreenCasting.Util +{ + public class CustomDevicePickerFilter + { + private IList supportedDeviceSelectors = new List(); + + public IList SupportedDeviceSelectors + { + get { return supportedDeviceSelectors; } + } + public override string ToString() + { + string retval = string.Empty; + + if (supportedDeviceSelectors.Count > 0) + retval = supportedDeviceSelectors[0]; + + if (supportedDeviceSelectors.Count > 1) + retval = "(" + retval + ")"; + + for (int idx = 1; idx < supportedDeviceSelectors.Count; idx++) + retval = retval + " OR (" + supportedDeviceSelectors[idx] + ")"; + + return retval; + } + } +} diff --git a/Samples/AdvancedCasting/cs/Util/DialLaunchArguments.cs b/Samples/AdvancedCasting/cs/Util/DialLaunchArguments.cs new file mode 100644 index 0000000000..38dfb4cb8f --- /dev/null +++ b/Samples/AdvancedCasting/cs/Util/DialLaunchArguments.cs @@ -0,0 +1,58 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScreenCasting.Util +{ + class DialLaunchArguments + { + public string VideoId { get; private set; } + public string PairingCode { get; private set; } + public TimeSpan Position { get; private set; } + + private DialLaunchArguments() { } + + public static DialLaunchArguments Parse(string arguments) + { + try + { + DialLaunchArguments dialLaunchArgs = new DialLaunchArguments(); + + string[] argswithkeys = arguments.Split('&'); + + foreach (string currentArgWithKey in argswithkeys) + { + string key = currentArgWithKey.Split('=')[0]; + string val = currentArgWithKey.Split('=')[1]; + switch (key) + { + case "v": { dialLaunchArgs.VideoId = val; break; } + case "t": { dialLaunchArgs.Position = TimeSpan.FromTicks(long.Parse(val)); break; } + case "pairingCode": { dialLaunchArgs.PairingCode = val; break; } + } + } + return dialLaunchArgs; + } + catch (Exception ex){ + throw new ArgumentOutOfRangeException(string.Format("Failed to parse DIAL launch arguments: '{0}'", arguments), ex); + } + } + + + } + + +} diff --git a/Samples/AdvancedCasting/cs/Util/RequiredDeviceProperties.cs b/Samples/AdvancedCasting/cs/Util/RequiredDeviceProperties.cs new file mode 100644 index 0000000000..9314804d33 --- /dev/null +++ b/Samples/AdvancedCasting/cs/Util/RequiredDeviceProperties.cs @@ -0,0 +1,60 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScreenCasting.Util +{ + public class RequiredDeviceProperties + { + public static readonly string DEVPKEY_AepContainer_FriendlyName = "{0bba1ede-7566-4f47-90ec-25fc567ced2a}, 5"; + public static readonly string DEVPKEY_AepContainer_SupportsAudio = "{6af55d45-38db-4495-acb0-d4728a3b8314}, 2"; + public static readonly string DEVPKEY_AepContainer_SupportsVideo = "{6af55d45-38db-4495-acb0-d4728a3b8314}, 3"; + public static readonly string DEVPKEY_AepContainer_SupportsImages = "{6af55d45-38db-4495-acb0-d4728a3b8314}, 4"; + public static readonly string DEVPKEY_AepContainer_SupportedUriSchemes = "{6af55d45-38db-4495-acb0-d4728a3b8314}, 5"; + public static readonly string DEVPKEY_AepContainer_Categories = "System.Devices.AepContainer.Categories"; + public static readonly string DEVPKEY_DeviceContainer_Manufacturer = "System.Devices.Manufacturer"; + public static readonly string DEVPKEY_DeviceContainer_ModelName = "System.Devices.ModelName"; + public static readonly string DEVPKEY_Device_ContainerId = "System.Devices.ContainerId"; + public static readonly string DEVPKEY_Device_InstanceId = "System.Devices.DeviceInstanceId"; + + private RequiredDeviceProperties() { } + + public static void AddProps(IList list) + { + foreach (string s in Props) + list.Add(s); + } + public static List Props + { + get + { + List properties = new List(); + properties.Add(RequiredDeviceProperties.DEVPKEY_AepContainer_FriendlyName); + properties.Add(RequiredDeviceProperties.DEVPKEY_AepContainer_SupportsAudio); + properties.Add(RequiredDeviceProperties.DEVPKEY_AepContainer_SupportsVideo); + properties.Add(RequiredDeviceProperties.DEVPKEY_AepContainer_SupportsImages); + properties.Add(RequiredDeviceProperties.DEVPKEY_AepContainer_SupportedUriSchemes); + properties.Add(RequiredDeviceProperties.DEVPKEY_AepContainer_Categories); + properties.Add(RequiredDeviceProperties.DEVPKEY_DeviceContainer_Manufacturer); + properties.Add(RequiredDeviceProperties.DEVPKEY_DeviceContainer_ModelName); + properties.Add(RequiredDeviceProperties.DEVPKEY_Device_ContainerId); + properties.Add(RequiredDeviceProperties.DEVPKEY_Device_InstanceId); + + return properties; + } + } + } +} diff --git a/Samples/AdvancedCasting/cs/Util/ViewLifetimeControl.cs b/Samples/AdvancedCasting/cs/Util/ViewLifetimeControl.cs new file mode 100644 index 0000000000..e3ecc73d2d --- /dev/null +++ b/Samples/AdvancedCasting/cs/Util/ViewLifetimeControl.cs @@ -0,0 +1,325 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +// The objects defined here demonstrate how to make sure each of the views created remains alive as long as +// the app needs them, but only when they're being used by the app or the user. Many of the scenarios contained in this +// sample use these functions to keep track of the views available and ensure that the view is not closed while +// the scenario is attempting to show it. +// +// As you can see in scenario 1, the ApplicationViewSwitcher.TryShowAsStandaloneAsync and +// ProjectionManager.StartProjectingAsync methods let you show one view next to another. The Consolidated event +// is fired when a view stops being visible separately from other views. Common cases where this will occur +// is when the view falls out of the list of recently used apps, or when the user performs the close gesture on the view. +// This is a good time to close the view, provided the app isn't trying to show the view at the same time. This event +// is fired on the thread of the view that becomes consolidated. +// +// Each view lives on its own thread, so concurrency control is necessary. Also, as you'll see in the sample, +// certain objects may be bound to UI on given threads. Properties of those objects should only be updated +// on that UI thread. + +using System; +using System.ComponentModel; +using Windows.UI.Core; +using Windows.UI.ViewManagement; + +namespace ScreenCasting.Util +{ + // A custom event that fires whenever the secondary view is ready to be closed. You should + // clean up any state (including deregistering for events) then close the window in this handler + public delegate void ViewReleasedHandler(Object sender, EventArgs e); + + // A ViewLifetimeControl is instantiated for every secondary view. ViewLifetimeControl's reference count + // keeps track of when the secondary view thinks it's in usem and when the main view is interacting with the secondary view (about to show + // it to the user, etc.) When the reference count drops to zero, the secondary view is closed. + public sealed class ViewLifetimeControl : INotifyPropertyChanged + { + // Dispatcher for this view. Kept here for sending messages between this view and the main view. + CoreDispatcher dispatcher; + + // Window for this particular view. Used to register and unregister for events + CoreWindow window; + + // The title for the view shown in the list of recently used apps (by setting the title on + // ApplicationView) + string title; + + // This class uses references counts to make sure the secondary views isn't closed prematurely. + // Whenever the main view is about to interact with the secondary view, it should take a reference + // by calling "StartViewInUse" on this object. When finished interacting, it should release the reference + // by calling "StopViewInUse". You can see examples of this throughout the sample, especially in + // scenario 1. + int refCount = 0; + + // Each view has a unique Id, found using the ApplicationView.Id property or + // ApplicationView.GetApplicationViewIdForCoreWindow method. This id is used in all of the ApplicationViewSwitcher + // and ProjectionManager APIs. + int viewId; + + // Tracks if this ViewLifetimeControl object is still valid. If this is true, then the view is in the process + // of closing itself down + bool released = false; + + // Keeps track of if the consolidated event has fired yet. A view is consolidated with other views + // when there's no way for the user to get to it (it's not in the list of recently used apps, cannot be + // launched from Start, etc.) A view stops being consolidated when it's visible--at that point + // the user can interact with it, move it on or off screen, etc. + bool consolidated = true; + + // Used to store pubicly registered events under the protection of a lock + event ViewReleasedHandler InternalReleased; + + // Instantiate views using "CreateForCurrentView" + private ViewLifetimeControl(CoreWindow newWindow) + { + dispatcher = newWindow.Dispatcher; + window = newWindow; + viewId = ApplicationView.GetApplicationViewIdForWindow(window); + + // This class will automatically tell the view when its time to close + // or stay alive in a few cases + RegisterForEvents(); + } + + // Register for events on the current view + private void RegisterForEvents() + { + // A view is consolidated with other views hen there's no way for the user to get to it (it's not in the list of recently used apps, cannot be + // launched from Start, etc.) A view stops being consolidated when it's visible--at that point the user can interact with it, move it on or off screen, etc. + // It's generally a good idea to close a view after it has been consolidated, but keep it open while it's visible. + ApplicationView.GetForCurrentView().Consolidated += ViewConsolidated; + window.VisibilityChanged += VisibilityChanged; + } + + // Unregister for events. Call this method before closing the view to prevent leaks. + private void UnregisterForEvents() + { + ApplicationView.GetForCurrentView().Consolidated -= ViewConsolidated; + window.VisibilityChanged -= VisibilityChanged; + } + + private void VisibilityChanged(object sender, VisibilityChangedEventArgs e) + { + + if (e.Visible) + { + // A view is consolidated with other views hen there's no way for the user to get to it (it's not in the list of recently used apps, cannot be + // launched from Start, etc.) A view stops being consolidated when it's visible--at that point the user can interact with it, move it on or off screen, etc. + // It's generally a good idea to close a view after it has been consolidated, but keep it open while it's visible. + Consolidated = false; + } + } + + // A view is consolidated with other views hen there's no way for the user to get to it (it's not in the list of recently used apps, cannot be + // launched from Start, etc.) A view stops being consolidated when it's visible--at that point the user can interact with it, move it on or off screen, etc. + // It's generally a good idea to close a view after it has been consolidated, but keep it open while it's visible. + private void ViewConsolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs e) + { + Consolidated = true; + } + + // Called when a view has been "consolidated" (no longer accessible to the user) + // and no other view is trying to interact with it. This should only be closed after the reference + // count goes to 0 (including being consolidated). At the end of this, the view is closed. + private void FinalizeRelease() + { + bool justReleased = false; + lock (this) + { + if (refCount == 0) + { + justReleased = true; + released = true; + } + } + + // This assumes that released will never be made false after it + // it has been set to true + if (justReleased) + { + UnregisterForEvents(); + InternalReleased(this, null); + } + } + + // Creates ViewLifetimeControl for the particular view. + // Only do this once per view. + public static ViewLifetimeControl CreateForCurrentView() + { + return new ViewLifetimeControl(CoreWindow.GetForCurrentThread()); + } + + // For purposes of this sample, the collection of views + // is bound to a UI collection. This property is available for binding + public string Title + { + get + { + return title; + } + set + { + if (title != value) + { + title = value; + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("Title")); + } + } + } + } + + // Necessary to communicate with the window + public CoreDispatcher Dispatcher + { + get + { + // This property never changes, so there's no need to lock + return dispatcher; + } + } + + // Each view has a unique Id, found using the ApplicationView.Id property or + // ApplicationView.GetApplicationViewIdForCoreWindow method. This id is used in all of the ApplicationViewSwitcher + // and ProjectionManager APIs. + public int Id + { + get + { + // This property never changes, so there's no need to lock + return viewId; + } + } + + // Keeps track of if the consolidated event has fired yet. A view is consolidated with other views + // when there's no way for the user to get to it (it's not in the list of recently used apps, cannot be + // launched from Start, etc.) A view stops being consolidated when it's visible--at that point + // the user can interact with it, move it on or off screen, etc. + public bool Consolidated + { + get + { + // This property should only be accessed by the thread on which the view lives, so there's no need to lock + return consolidated; + } + set + { + if (consolidated != value) + { + consolidated = value; + if (consolidated) + { + // The view isn't accessible to the user, so it's OK to close it. + StopViewInUse(); + } + else + { + // The view has become visible, so do not close it until it's consolidated + StartViewInUse(); + } + } + } + } + + // Signals that the view is being interacted with by another view, + // so it shouldn't be closed even if it becomes "consolidated" + public int StartViewInUse() + { + bool releasedCopy = false; + int refCountCopy = 0; + + // This method is called from several different threads + // (each view lives on its own thread) + lock (this) + { + releasedCopy = this.released; + if (!released) + { + refCountCopy = ++refCount; + } + } + + if (releasedCopy) + { + throw new InvalidOperationException("This view is being disposed"); + } + + return refCountCopy; + } + + // Should come after any call to StartViewInUse + // Signals that the another view has finished interacting with the view tracked + // by this object + public int StopViewInUse() + { + int refCountCopy = 0; + bool releasedCopy = false; + + lock (this) + { + releasedCopy = this.released; + if (!released) + { + refCountCopy = --refCount; + if (refCountCopy == 0) + { + // If no other view is interacting with this view, and + // the view isn't accessible to the user, it's appropriate + // to close it + // + // Before actually closing the view, make sure there are no + // other important events waiting in the queue (this low-priority item + // will run after other events) + dispatcher.RunAsync(CoreDispatcherPriority.Low, FinalizeRelease); + } + } + } + + if (releasedCopy) + { + throw new InvalidOperationException("This view is being disposed"); + } + return refCountCopy; + } + + // Signals to consumers that its time to close the view so that + // they can clean up (including calling Window.Close() when finished) + public event PropertyChangedEventHandler PropertyChanged; + public event ViewReleasedHandler Released + { + add + { + bool releasedCopy = false; + lock (this) + { + releasedCopy = released; + if (!released) + { + InternalReleased += value; + } + } + + if (releasedCopy) + { + throw new InvalidOperationException("This view is being disposed"); + } + } + + remove + { + lock (this) + { + InternalReleased -= value; + } + } + } + } +} diff --git a/Samples/AdvancedCasting/cs/project.json b/Samples/AdvancedCasting/cs/project.json new file mode 100644 index 0000000000..c594939270 --- /dev/null +++ b/Samples/AdvancedCasting/cs/project.json @@ -0,0 +1,16 @@ +{ + "dependencies": { + "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0" + }, + "frameworks": { + "uap10.0": {} + }, + "runtimes": { + "win10-arm": {}, + "win10-arm-aot": {}, + "win10-x86": {}, + "win10-x86-aot": {}, + "win10-x64": {}, + "win10-x64-aot": {} + } +} \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h new file mode 100644 index 0000000000..45fa60fccb --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h @@ -0,0 +1,54 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +public interface class ISecureInterfaceService +{ +public: + // Implement this function to handle calls to the Concatenate method. + Windows::Foundation::IAsyncOperation^ ConcatenateAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info , _In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2); + + // Implement this function to handle requests for the value of the IsUpperCaseEnabled property. + // + // Currently, info will always be null, because no information is available about the requestor. + Windows::Foundation::IAsyncOperation^ GetIsUpperCaseEnabledAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + // Implement this function to handle requests to set the IsUpperCaseEnabled property. + // + // Currently, info will always be null, because no information is available about the requestor. + Windows::Foundation::IAsyncOperation^ SetIsUpperCaseEnabledAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, bool value); + +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1IntrospectionXml.xml b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1IntrospectionXml.xml new file mode 100644 index 0000000000..366ad9383e --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1IntrospectionXml.xml @@ -0,0 +1,20 @@ + + + A secure AllJoyn sample + + + Concatenate two input strings and returns the concatenated string as output + + + + + + Determine if the output of the Concatenate method is returned as upper case string or not + + + + This signal is emitted when producer sends a text message to consumer + + + + diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj new file mode 100644 index 0000000000..49551a4d07 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj @@ -0,0 +1,260 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {0a9e8245-5676-4b45-b34b-756927d85b3c} + WindowsRuntimeComponent + Scenario1WinRTComponent + com.microsoft.Samples.SecureInterface + en-US + 14.0 + true + Windows Store + 10.0 + 10.0.10240.0 + 10.0.10240.0 + true + + + + DynamicLibrary + true + v140 + + + DynamicLibrary + true + v140 + + + DynamicLibrary + true + v140 + + + DynamicLibrary + false + true + v140 + true + + + DynamicLibrary + false + true + v140 + true + + + DynamicLibrary + false + true + v140 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + false + + + false + + + $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\shared + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters new file mode 100644 index 0000000000..3288c2691e --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + aa05969e-0ba6-407c-9c26-91ed00b63b8b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp new file mode 100644 index 0000000000..8b79c09f40 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp @@ -0,0 +1,408 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Devices::AllJoyn; +using namespace com::microsoft::Samples::SecureInterface; + +std::map SecureInterfaceConsumer::SourceInterfaces; + +SecureInterfaceConsumer::SecureInterfaceConsumer(AllJoynBusAttachment^ busAttachment) + : m_busAttachment(busAttachment), + m_proxyBusObject(nullptr), + m_busObject(nullptr), + m_sessionListener(nullptr), + m_sessionId(0) +{ + m_weak = new WeakReference(this); + m_signals = ref new SecureInterfaceSignals(); + m_nativeBusAttachment = AllJoynHelpers::GetInternalBusAttachment(m_busAttachment); +} + +SecureInterfaceConsumer::~SecureInterfaceConsumer() +{ + AllJoynBusObjectManager::ReleaseBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data()); + if (SessionListener != nullptr) + { + alljoyn_busattachment_setsessionlistener(m_nativeBusAttachment, m_sessionId, nullptr); + alljoyn_sessionlistener_destroy(SessionListener); + } + if (nullptr != ProxyBusObject) + { + alljoyn_proxybusobject_destroy(ProxyBusObject); + } + delete m_weak; +} + +void SecureInterfaceConsumer::OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) +{ + if (sessionId == m_sessionId) + { + AllJoynSessionLostEventArgs^ args = ref new AllJoynSessionLostEventArgs(static_cast(reason)); + SessionLost(this, args); + } +} + +void SecureInterfaceConsumer::OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberAddedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + SessionMemberAdded(this, args); + } +} + +void SecureInterfaceConsumer::OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberRemovedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + SessionMemberRemoved(this, args); + } +} + +QStatus SecureInterfaceConsumer::AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler) +{ + alljoyn_interfacedescription_member member; + if (!alljoyn_interfacedescription_getmember(interfaceDescription, methodName, &member)) + { + return ER_BUS_INTERFACE_NO_SUCH_MEMBER; + } + + return alljoyn_busattachment_registersignalhandler(busAttachment, handler, member, NULL); +} + +IAsyncOperation^ SecureInterfaceConsumer::JoinSessionAsync( + _In_ AllJoynServiceInfo^ serviceInfo, _Inout_ SecureInterfaceWatcher^ watcher) +{ + return create_async([serviceInfo, watcher]() -> SecureInterfaceJoinSessionResult^ + { + auto result = ref new SecureInterfaceJoinSessionResult(); + result->Status = AllJoynStatus::Ok; + result->Consumer = nullptr; + + result->Consumer = ref new SecureInterfaceConsumer(watcher->BusAttachment); + result->Status = result->Consumer->JoinSession(serviceInfo); + + return result; + }); +} + +IAsyncOperation^ SecureInterfaceConsumer::ConcatenateAsync(_In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2) +{ + return create_async([this, interfaceMemberInStr1, interfaceMemberInStr2]() -> SecureInterfaceConcatenateResult^ + { + auto result = ref new SecureInterfaceConcatenateResult(); + + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); + size_t argCount = 2; + alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); + + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 0), "s", interfaceMemberInStr1); + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 1), "s", interfaceMemberInStr2); + + QStatus status = alljoyn_proxybusobject_methodcall( + ProxyBusObject, + "com.microsoft.Samples.SecureInterface", + "Concatenate", + inputs, + argCount, + message, + c_MessageTimeoutInMilliseconds, + 0); + result->Status = static_cast(status); + if (ER_OK == status) + { + result->Status = AllJoynStatus::Ok; + Platform::String^ argument0; + status = static_cast(TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "s", &argument0)); + result->OutStr = argument0; + + if (status != ER_OK) + { + result->Status = static_cast(status); + } + } + else if (ER_BUS_REPLY_IS_ERROR_MESSAGE == status) + { + alljoyn_msgarg errorArg = alljoyn_message_getarg(message, 1); + if (nullptr != errorArg) + { + uint16 errorStatus; + status = alljoyn_msgarg_get_uint16(errorArg, &errorStatus); + if (ER_OK == status) + { + status = static_cast(errorStatus); + } + } + result->Status = static_cast(status); + } + + alljoyn_message_destroy(message); + alljoyn_msgarg_destroy(inputs); + + return result; + }); +} + +IAsyncOperation^ SecureInterfaceConsumer::SetIsUpperCaseEnabledAsync(_In_ bool value) +{ + return create_async([this, value]() -> SecureInterfaceSetIsUpperCaseEnabledResult^ + { + PropertySetContext setContext; + + alljoyn_msgarg inputArgument = alljoyn_msgarg_create(); + TypeConversionHelpers::SetAllJoynMessageArg(inputArgument, "b", value); + + alljoyn_proxybusobject_setpropertyasync( + ProxyBusObject, + "com.microsoft.Samples.SecureInterface", + "IsUpperCaseEnabled", + inputArgument, + [](QStatus status, alljoyn_proxybusobject obj, void* context) + { + UNREFERENCED_PARAMETER(obj); + auto propertyContext = static_cast(context); + propertyContext->SetStatus(status); + propertyContext->SetEvent(); + }, + c_MessageTimeoutInMilliseconds, + &setContext); + + alljoyn_msgarg_destroy(inputArgument); + + setContext.Wait(); + + auto result = ref new SecureInterfaceSetIsUpperCaseEnabledResult(); + result->Status = setContext.GetStatus(); + return result; + }); +} + +IAsyncOperation^ SecureInterfaceConsumer::GetIsUpperCaseEnabledAsync() +{ + return create_async([this]() -> SecureInterfaceGetIsUpperCaseEnabledResult^ + { + PropertyGetContext getContext; + + alljoyn_proxybusobject_getpropertyasync( + ProxyBusObject, + "com.microsoft.Samples.SecureInterface", + "IsUpperCaseEnabled", + [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) + { + UNREFERENCED_PARAMETER(obj); + auto propertyContext = static_cast*>(context); + + if (ER_OK == status) + { + bool argument; + TypeConversionHelpers::GetAllJoynMessageArg(value, "b", &argument); + + propertyContext->SetValue(argument); + } + propertyContext->SetStatus(status); + propertyContext->SetEvent(); + }, + c_MessageTimeoutInMilliseconds, + &getContext); + + getContext.Wait(); + + auto result = ref new SecureInterfaceGetIsUpperCaseEnabledResult(); + result->Status = getContext.GetStatus(); + result->IsUpperCaseEnabled = getContext.GetValue(); + return result; + }); +} + +void SecureInterfaceConsumer::OnPropertyChanged(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated) +{ + UNREFERENCED_PARAMETER(obj); + UNREFERENCED_PARAMETER(interfaceName); + UNREFERENCED_PARAMETER(invalidated); + + alljoyn_msgarg changedProperties; + size_t changedPropertyCount; + if (ER_OK != alljoyn_msgarg_get(changed, "a{sv}", &changedPropertyCount, &changedProperties)) + { + return; + } + + for (size_t i = 0; i < changedPropertyCount; i++) + { + char* propertyName; + alljoyn_msgarg propertyValue; + if (ER_OK != alljoyn_msgarg_get(alljoyn_msgarg_array_element(changedProperties, i), "{sv}", &propertyName, &propertyValue)) + { + return; + } + + if (strcmp("IsUpperCaseEnabled", propertyName) == 0) + { + IsUpperCaseEnabledChanged(this, nullptr); + } + } +} + +void SecureInterfaceConsumer::CallTextSentSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message) +{ + auto source = SourceInterfaces.find(member->iface); + if (source == SourceInterfaces.end()) + { + return; + } + + auto consumer = source->second->Resolve(); + if (consumer->Signals != nullptr) + { + auto callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + auto eventArgs = ref new SecureInterfaceTextSentReceivedEventArgs(); + eventArgs->MessageInfo = callInfo; + + Platform::String^ argument0; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "s", &argument0); + + eventArgs->Message = argument0; + + consumer->Signals->CallTextSentReceived(consumer->Signals, eventArgs); + } +} + +int32 SecureInterfaceConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) +{ + alljoyn_sessionlistener_callbacks callbacks = + { + AllJoynHelpers::SessionLostHandler, + AllJoynHelpers::SessionMemberAddedHandler, + AllJoynHelpers::SessionMemberRemovedHandler + }; + + alljoyn_busattachment_enableconcurrentcallbacks(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment)); + + SessionListener = alljoyn_sessionlistener_create(&callbacks, m_weak); + alljoyn_sessionopts sessionOpts = alljoyn_sessionopts_create(ALLJOYN_TRAFFIC_TYPE_MESSAGES, true, ALLJOYN_PROXIMITY_ANY, ALLJOYN_TRANSPORT_ANY); + + std::vector sessionNameUtf8 = AllJoynHelpers::PlatformToMultibyteString(serviceInfo->UniqueName); + RETURN_IF_QSTATUS_ERROR(alljoyn_busattachment_joinsession( + m_nativeBusAttachment, + &sessionNameUtf8[0], + serviceInfo->SessionPort, + SessionListener, + &m_sessionId, + sessionOpts)); + alljoyn_sessionopts_destroy(sessionOpts); + + ServiceObjectPath = serviceInfo->ObjectPath; + std::vector objectPath = AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath); + + if (objectPath.empty()) + { + return AllJoynStatus::Fail; + } + + ProxyBusObject = alljoyn_proxybusobject_create(m_nativeBusAttachment, &sessionNameUtf8[0], &objectPath[0], m_sessionId); + if (nullptr == ProxyBusObject) + { + return AllJoynStatus::Fail; + } + + PCSTR propertyNames[] = { "IsUpperCaseEnabled" }; + + RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_registerpropertieschangedlistener( + ProxyBusObject, + "com.microsoft.Samples.SecureInterface", + propertyNames, + _countof(propertyNames), + AllJoynHelpers::PropertyChangedHandler, + m_weak)); + + + alljoyn_interfacedescription description = alljoyn_busattachment_getinterface(m_nativeBusAttachment, "com.microsoft.Samples.SecureInterface"); + if (nullptr == description) + { + return AllJoynStatus::Fail; + } + + unsigned int noneMechanismIndex = 0; + bool authenticationMechanismsContainsNone = m_busAttachment->AuthenticationMechanisms->IndexOf(AllJoynAuthenticationMechanism::None, &noneMechanismIndex); + QCC_BOOL interfaceIsSecure = alljoyn_interfacedescription_issecure(description); + + // If the current set of AuthenticationMechanisms supports authentication, + // determine whether to secure the connection. + if (AllJoynHelpers::CanSecure(m_busAttachment->AuthenticationMechanisms)) + { + // Secure the connection if the org.alljoyn.Bus.Secure XML annotation + // is specified, or if None is not present in AuthenticationMechanisms. + if (!authenticationMechanismsContainsNone || interfaceIsSecure) + { + alljoyn_proxybusobject_secureconnection(ProxyBusObject, QCC_FALSE); + } + } + else + { + // If the current set of AuthenticationMechanisms does not support authentication + // but the interface requires security, report an error. + if (interfaceIsSecure) + { + return static_cast(ER_BUS_NO_AUTHENTICATION_MECHANISM); + } + } + + RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::GetBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data(), &m_busObject)); + RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_addinterface(ProxyBusObject, description)); + + if (!AllJoynBusObjectManager::BusObjectIsRegistered(m_nativeBusAttachment, m_busObject)) + { + RETURN_IF_QSTATUS_ERROR(alljoyn_busobject_addinterface(BusObject, description)); + } + + QStatus result = AddSignalHandler( + m_nativeBusAttachment, + description, + "TextSent", + [](const alljoyn_interfacedescription_member* member, PCSTR srcPath, alljoyn_message message) { UNREFERENCED_PARAMETER(srcPath); CallTextSentSignalHandler(member, message); }); + if (result != ER_OK) + { + return static_cast(result); + } + + SourceInterfaces[description] = m_weak; + RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, true)); + m_signals->Initialize(BusObject, m_sessionId); + + return AllJoynStatus::Ok; +} diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h new file mode 100644 index 0000000000..a6458b085f --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h @@ -0,0 +1,159 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +public interface class ISecureInterfaceConsumer +{ + event Windows::Foundation::TypedEventHandler^ SessionLost; + event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; + event Windows::Foundation::TypedEventHandler^ IsUpperCaseEnabledChanged; +}; + +public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceConsumer +{ +public: + SecureInterfaceConsumer(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + virtual ~SecureInterfaceConsumer(); + + // Join the AllJoyn session specified by sessionName. + // + // This will usually be called after the unique name of a producer has been reported + // in the Added callback on the Watcher. + static Windows::Foundation::IAsyncOperation^ JoinSessionAsync(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo, _Inout_ SecureInterfaceWatcher^ watcher); + + // Call the Concatenate method + Windows::Foundation::IAsyncOperation^ ConcatenateAsync(_In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2); + // This event fires whenever the value of IsUpperCaseEnabled changes. + virtual event Windows::Foundation::TypedEventHandler^ IsUpperCaseEnabledChanged; + + // Get the value of the IsUpperCaseEnabled property. + Windows::Foundation::IAsyncOperation^ GetIsUpperCaseEnabledAsync(); + + // Set the value of the IsUpperCaseEnabled property. + Windows::Foundation::IAsyncOperation^ SetIsUpperCaseEnabledAsync(_In_ bool value); + + // Used to send signals or register functions to handle received signals. + property SecureInterfaceSignals^ Signals + { + SecureInterfaceSignals^ get() { return m_signals; } + } + + // This event will fire whenever the consumer loses the session that it is a member of. + virtual event Windows::Foundation::TypedEventHandler^ SessionLost; + + // This event will fire whenever a member joins the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + + // This event will fire whenever a member leaves the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; + +internal: + // Consumers do not support property get. + QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val) + { + UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); + return ER_NOT_IMPLEMENTED; + } + + // Consumers do not support property set. + QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val) + { + UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); + return ER_NOT_IMPLEMENTED; + } + + void OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason); + void OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + void OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + + void OnPropertyChanged(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated); + + property Platform::String^ ServiceObjectPath + { + Platform::String^ get() { return m_ServiceObjectPath; } + void set(Platform::String^ value) { m_ServiceObjectPath = value; } + } + + property alljoyn_proxybusobject ProxyBusObject + { + alljoyn_proxybusobject get() { return m_proxyBusObject; } + void set(alljoyn_proxybusobject value) { m_proxyBusObject = value; } + } + + property alljoyn_busobject BusObject + { + alljoyn_busobject get() { return m_busObject; } + void set(alljoyn_busobject value) { m_busObject = value; } + } + + property alljoyn_sessionlistener SessionListener + { + alljoyn_sessionlistener get() { return m_sessionListener; } + void set(alljoyn_sessionlistener value) { m_sessionListener = value; } + } + + property alljoyn_sessionid SessionId + { + alljoyn_sessionid get() { return m_sessionId; } + } + +private: + int32 JoinSession(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo); + + // Register a callback function to handle incoming signals. + QStatus AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler); + + static void CallTextSentSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); + + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + SecureInterfaceSignals^ m_signals; + Platform::String^ m_ServiceObjectPath; + + alljoyn_proxybusobject m_proxyBusObject; + alljoyn_busobject m_busObject; + alljoyn_sessionlistener m_sessionListener; + alljoyn_sessionid m_sessionId; + alljoyn_busattachment m_nativeBusAttachment; + + // Used to pass a pointer to this class to callbacks + Platform::WeakReference* m_weak; + + // This map is required because we need a way to pass the consumer to the signal + // handlers, but the current AllJoyn C API does not allow passing a context to these + // callbacks. + static std::map SourceInterfaces; +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h new file mode 100644 index 0000000000..bf3f9a7268 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h @@ -0,0 +1,60 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +// Signals +public ref class SecureInterfaceTextSentReceivedEventArgs sealed +{ +public: + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + void set(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ value) { m_messageInfo = value; } + } + + property Platform::String^ Message + { + Platform::String^ get() { return m_interfaceMemberMessage; } + internal: + void set(_In_ Platform::String^ value) { m_interfaceMemberMessage = value; } + } + +private: + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + + Platform::String^ m_interfaceMemberMessage; +}; + + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h new file mode 100644 index 0000000000..309f856e8b --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h @@ -0,0 +1,162 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +ref class SecureInterfaceConsumer; + +public ref class SecureInterfaceConcatenateResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property Platform::String^ OutStr + { + Platform::String^ get() { return m_interfaceMemberOutStr; } + internal: + void set(_In_ Platform::String^ value) { m_interfaceMemberOutStr = value; } + } + + static SecureInterfaceConcatenateResult^ CreateSuccessResult(_In_ Platform::String^ interfaceMemberOutStr) + { + auto result = ref new SecureInterfaceConcatenateResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->OutStr = interfaceMemberOutStr; + return result; + } + + static SecureInterfaceConcatenateResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new SecureInterfaceConcatenateResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + Platform::String^ m_interfaceMemberOutStr; +}; + +public ref class SecureInterfaceJoinSessionResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property SecureInterfaceConsumer^ Consumer + { + SecureInterfaceConsumer^ get() { return m_consumer; } + internal: + void set(_In_ SecureInterfaceConsumer^ value) { m_consumer = value; } + }; + +private: + int32 m_status; + SecureInterfaceConsumer^ m_consumer; +}; + +public ref class SecureInterfaceGetIsUpperCaseEnabledResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property bool IsUpperCaseEnabled + { + bool get() { return m_value; } + internal: + void set(_In_ bool value) { m_value = value; } + } + + static SecureInterfaceGetIsUpperCaseEnabledResult^ CreateSuccessResult(_In_ bool value) + { + auto result = ref new SecureInterfaceGetIsUpperCaseEnabledResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->IsUpperCaseEnabled = value; + return result; + } + + static SecureInterfaceGetIsUpperCaseEnabledResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new SecureInterfaceGetIsUpperCaseEnabledResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + bool m_value; +}; + +public ref class SecureInterfaceSetIsUpperCaseEnabledResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + static SecureInterfaceSetIsUpperCaseEnabledResult^ CreateSuccessResult() + { + auto result = ref new SecureInterfaceSetIsUpperCaseEnabledResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + return result; + } + + static SecureInterfaceSetIsUpperCaseEnabledResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new SecureInterfaceSetIsUpperCaseEnabledResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp new file mode 100644 index 0000000000..ca583b5871 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp @@ -0,0 +1,457 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Devices::AllJoyn; +using namespace com::microsoft::Samples::SecureInterface; + +std::map SecureInterfaceProducer::SourceObjects; +std::map SecureInterfaceProducer::SourceInterfaces; + +SecureInterfaceProducer::SecureInterfaceProducer(AllJoynBusAttachment^ busAttachment) + : m_busAttachment(busAttachment), + m_sessionListener(nullptr), + m_busObject(nullptr), + m_sessionPort(0), + m_sessionId(0) +{ + m_weak = new WeakReference(this); + ServiceObjectPath = ref new String(L"/Service"); + m_signals = ref new SecureInterfaceSignals(); + m_busAttachmentStateChangedToken.Value = 0; +} + +SecureInterfaceProducer::~SecureInterfaceProducer() +{ + UnregisterFromBus(); + delete m_weak; +} + +void SecureInterfaceProducer::UnregisterFromBus() +{ + if ((nullptr != m_busAttachment) && (0 != m_busAttachmentStateChangedToken.Value)) + { + m_busAttachment->StateChanged -= m_busAttachmentStateChangedToken; + m_busAttachmentStateChangedToken.Value = 0; + } + if (nullptr != SessionPortListener) + { + alljoyn_busattachment_unbindsessionport(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), m_sessionPort); + alljoyn_sessionportlistener_destroy(SessionPortListener); + SessionPortListener = nullptr; + } + if (nullptr != BusObject) + { + alljoyn_busattachment_unregisterbusobject(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + alljoyn_busobject_destroy(BusObject); + BusObject = nullptr; + } + if (nullptr != SessionListener) + { + alljoyn_sessionlistener_destroy(SessionListener); + SessionListener = nullptr; + } +} + +bool SecureInterfaceProducer::OnAcceptSessionJoiner(_In_ alljoyn_sessionport sessionPort, _In_ PCSTR joiner, _In_ const alljoyn_sessionopts opts) +{ + UNREFERENCED_PARAMETER(sessionPort); UNREFERENCED_PARAMETER(joiner); UNREFERENCED_PARAMETER(opts); + + return true; +} + +void SecureInterfaceProducer::OnSessionJoined(_In_ alljoyn_sessionport sessionPort, _In_ alljoyn_sessionid id, _In_ PCSTR joiner) +{ + UNREFERENCED_PARAMETER(joiner); + + // We initialize the Signals object after the session has been joined, because it needs + // the session id. + m_signals->Initialize(BusObject, id); + m_sessionPort = sessionPort; + m_sessionId = id; + + alljoyn_sessionlistener_callbacks callbacks = + { + AllJoynHelpers::SessionLostHandler, + AllJoynHelpers::SessionMemberAddedHandler, + AllJoynHelpers::SessionMemberRemovedHandler + }; + + SessionListener = alljoyn_sessionlistener_create(&callbacks, m_weak); + alljoyn_busattachment_setsessionlistener(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), id, SessionListener); +} + +void SecureInterfaceProducer::OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) +{ + if (sessionId == m_sessionId) + { + AllJoynSessionLostEventArgs^ args = ref new AllJoynSessionLostEventArgs(static_cast(reason)); + AllJoynHelpers::DispatchEvent([=]() { + SessionLost(this, args); + }); + } +} + +void SecureInterfaceProducer::OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberAddedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + AllJoynHelpers::DispatchEvent([=]() { + SessionMemberAdded(this, args); + }); + } +} + +void SecureInterfaceProducer::OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberRemovedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + AllJoynHelpers::DispatchEvent([=]() { + SessionMemberRemoved(this, args); + }); + } +} + +void SecureInterfaceProducer::BusAttachmentStateChanged(_In_ AllJoynBusAttachment^ sender, _In_ AllJoynBusAttachmentStateChangedEventArgs^ args) +{ + if (args->State == AllJoynBusAttachmentState::Connected) + { + QStatus result = AllJoynHelpers::CreateProducerSession(m_busAttachment, m_weak); + if (ER_OK != result) + { + StopInternal(result); + return; + } + } + else if (args->State == AllJoynBusAttachmentState::Disconnected) + { + StopInternal(ER_BUS_STOPPING); + } +} + +void SecureInterfaceProducer::CallConcatenateHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message) +{ + auto source = SourceObjects.find(busObject); + if (source == SourceObjects.end()) + { + return; + } + + SecureInterfaceProducer^ producer = source->second->Resolve(); + if (producer->Service != nullptr) + { + AllJoynMessageInfo^ callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + + Platform::String^ inputArg0; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "s", &inputArg0); + Platform::String^ inputArg1; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 1), "s", &inputArg1); + + create_task(producer->Service->ConcatenateAsync(callInfo, inputArg0, inputArg1)).then([busObject, message](SecureInterfaceConcatenateResult^ result) + { + int32 status; + + if (nullptr == result) + { + alljoyn_busobject_methodreply_status(busObject, message, ER_BUS_NO_LISTENER); + return; + } + + status = result->Status; + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + return; + } + + size_t argCount = 1; + alljoyn_msgarg outputs = alljoyn_msgarg_array_create(argCount); + + status = TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(outputs, 0), "s", result->OutStr); + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + alljoyn_msgarg_destroy(outputs); + return; + } + + alljoyn_busobject_methodreply_args(busObject, message, outputs, argCount); + alljoyn_msgarg_destroy(outputs); + }).wait(); + } +} + +void SecureInterfaceProducer::CallTextSentSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message) +{ + auto source = SourceInterfaces.find(member->iface); + if (source == SourceInterfaces.end()) + { + return; + } + + auto producer = source->second->Resolve(); + if (producer->Signals != nullptr) + { + auto callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + auto eventArgs = ref new SecureInterfaceTextSentReceivedEventArgs(); + eventArgs->MessageInfo = callInfo; + + Platform::String^ argument0; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "s", &argument0); + eventArgs->Message = argument0; + + producer->Signals->CallTextSentReceived(producer->Signals, eventArgs); + } +} + +QStatus SecureInterfaceProducer::AddMethodHandler(_In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_methodhandler_ptr handler) +{ + alljoyn_interfacedescription_member member; + if (!alljoyn_interfacedescription_getmember(interfaceDescription, methodName, &member)) + { + return ER_BUS_INTERFACE_NO_SUCH_MEMBER; + } + + return alljoyn_busobject_addmethodhandler( + m_busObject, + member, + handler, + m_weak); +} + +QStatus SecureInterfaceProducer::AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler) +{ + alljoyn_interfacedescription_member member; + if (!alljoyn_interfacedescription_getmember(interfaceDescription, methodName, &member)) + { + return ER_BUS_INTERFACE_NO_SUCH_MEMBER; + } + + return alljoyn_busattachment_registersignalhandler(busAttachment, handler, member, NULL); +} + +QStatus SecureInterfaceProducer::OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg value) +{ + UNREFERENCED_PARAMETER(interfaceName); + + if (0 == strcmp(propertyName, "IsUpperCaseEnabled")) + { + auto task = create_task(Service->GetIsUpperCaseEnabledAsync(nullptr)); + auto result = task.get(); + + if (AllJoynStatus::Ok != result->Status) + { + return static_cast(result->Status); + } + + return static_cast(TypeConversionHelpers::SetAllJoynMessageArg(value, "b", result->IsUpperCaseEnabled)); + } + + return ER_BUS_NO_SUCH_PROPERTY; +} + +QStatus SecureInterfaceProducer::OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg value) +{ + UNREFERENCED_PARAMETER(interfaceName); + + if (0 == strcmp(propertyName, "IsUpperCaseEnabled")) + { + bool argument; + TypeConversionHelpers::GetAllJoynMessageArg(value, "b", &argument); + + auto task = create_task(Service->SetIsUpperCaseEnabledAsync(nullptr, argument)); + auto result = task.get(); + + return static_cast(result->Status); + } + return ER_BUS_NO_SUCH_PROPERTY; +} + +void SecureInterfaceProducer::EmitIsUpperCaseEnabledChanged() +{ + create_task([&] + { + alljoyn_msgarg value = alljoyn_msgarg_create(); + OnPropertyGet("com.microsoft.Samples.SecureInterface", "IsUpperCaseEnabled", value); + + alljoyn_busobject_emitpropertychanged( + m_busObject, + "com.microsoft.Samples.SecureInterface", + "IsUpperCaseEnabled", + value, + m_sessionId); + + alljoyn_msgarg_destroy(value); + }); +} + +void SecureInterfaceProducer::Start() +{ + if (nullptr == m_busAttachment) + { + StopInternal(ER_FAIL); + return; + } + + QStatus result = AllJoynHelpers::CreateInterfaces(m_busAttachment, c_SecureInterfaceIntrospectionXml); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AllJoynHelpers::CreateBusObject(m_weak); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + alljoyn_interfacedescription interfaceDescription = alljoyn_busattachment_getinterface(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), "com.microsoft.Samples.SecureInterface"); + if (interfaceDescription == nullptr) + { + StopInternal(ER_FAIL); + return; + } + alljoyn_busobject_addinterface_announced(BusObject, interfaceDescription); + + result = AddMethodHandler( + interfaceDescription, + "Concatenate", + [](alljoyn_busobject busObject, const alljoyn_interfacedescription_member* member, alljoyn_message message) { UNREFERENCED_PARAMETER(member); CallConcatenateHandler(busObject, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AddSignalHandler( + AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), + interfaceDescription, + "TextSent", + [](const alljoyn_interfacedescription_member* member, PCSTR srcPath, alljoyn_message message) { UNREFERENCED_PARAMETER(srcPath); CallTextSentSignalHandler(member, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + SourceObjects[m_busObject] = m_weak; + SourceInterfaces[interfaceDescription] = m_weak; + + unsigned int noneMechanismIndex = 0; + bool authenticationMechanismsContainsNone = m_busAttachment->AuthenticationMechanisms->IndexOf(AllJoynAuthenticationMechanism::None, &noneMechanismIndex); + QCC_BOOL interfaceIsSecure = alljoyn_interfacedescription_issecure(interfaceDescription); + + // If the current set of AuthenticationMechanisms supports authentication, + // determine whether a secure BusObject is required. + if (AllJoynHelpers::CanSecure(m_busAttachment->AuthenticationMechanisms)) + { + // Register the BusObject as "secure" if the org.alljoyn.Bus.Secure XML annotation + // is specified, or if None is not present in AuthenticationMechanisms. + if (!authenticationMechanismsContainsNone || interfaceIsSecure) + { + result = alljoyn_busattachment_registerbusobject_secure(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + } + else + { + result = alljoyn_busattachment_registerbusobject(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + } + } + else + { + // If the current set of AuthenticationMechanisms does not support authentication + // but the interface requires security, report an error. + if (interfaceIsSecure) + { + result = ER_BUS_NO_AUTHENTICATION_MECHANISM; + } + else + { + result = alljoyn_busattachment_registerbusobject(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + } + } + + if (result != ER_OK) + { + StopInternal(result); + return; + } + + m_busAttachmentStateChangedToken = m_busAttachment->StateChanged += ref new TypedEventHandler(this, &SecureInterfaceProducer::BusAttachmentStateChanged); + m_busAttachment->Connect(); +} + +void SecureInterfaceProducer::Stop() +{ + StopInternal(AllJoynStatus::Ok); +} + +void SecureInterfaceProducer::StopInternal(int32 status) +{ + UnregisterFromBus(); + Stopped(this, ref new AllJoynProducerStoppedEventArgs(status)); +} + +int32 SecureInterfaceProducer::RemoveMemberFromSession(_In_ String^ uniqueName) +{ + return alljoyn_busattachment_removesessionmember( + AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), + m_sessionId, + AllJoynHelpers::PlatformToMultibyteString(uniqueName).data()); +} + +PCSTR com::microsoft::Samples::SecureInterface::c_SecureInterfaceIntrospectionXml = "" +" A secure AllJoyn sample" +" " +" " +" Method that concatenates two input strings and returns the concatenated string as output" +" " +" " +" " +" " +" " +" Property to determine if the output of the Concatenate method is returned as upper case string or not" +" " +" " +" " +" Signal to send a text message" +" " +" " +"" +; diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h new file mode 100644 index 0000000000..c16af8d209 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h @@ -0,0 +1,174 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +extern PCSTR c_SecureInterfaceIntrospectionXml; + +ref class SecureInterfaceProducer; + +public interface class ISecureInterfaceProducer +{ + event Windows::Foundation::TypedEventHandler^ Stopped; + event Windows::Foundation::TypedEventHandler^ SessionLost; + event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; +}; + +public ref class SecureInterfaceProducer sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceProducer +{ +public: + SecureInterfaceProducer(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + virtual ~SecureInterfaceProducer(); + + // The implementation of ISecureInterfaceService that will handle method calls and property requests. + property ISecureInterfaceService^ Service + { + ISecureInterfaceService^ get() { return m_serviceInterface; } + void set(ISecureInterfaceService^ value) { m_serviceInterface = value; } + } + + // Used to send signals or register functions to handle received signals. + property SecureInterfaceSignals^ Signals + { + SecureInterfaceSignals^ get() { return m_signals; } + } + + // This event will fire whenever this producer is stopped. + virtual event Windows::Foundation::TypedEventHandler^ Stopped; + + // This event will fire whenever the producer loses the session that it created. + virtual event Windows::Foundation::TypedEventHandler^ SessionLost; + + // This event will fire whenever a member joins the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + + // This event will fire whenever a member leaves the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; + + // Send a signal to all members of the session to notify them that the value of IsUpperCaseEnabled has changed. + void EmitIsUpperCaseEnabledChanged(); + + // Start advertising the service. + void Start(); + + // Stop advertising the service. + void Stop(); + + // Remove a member that has joined this session. + int32 RemoveMemberFromSession(_In_ Platform::String^ uniqueName); + +internal: + bool OnAcceptSessionJoiner(_In_ alljoyn_sessionport sessionPort, _In_ PCSTR joiner, _In_ const alljoyn_sessionopts opts); + void OnSessionJoined(_In_ alljoyn_sessionport sessionPort, _In_ alljoyn_sessionid id, _In_ PCSTR joiner); + QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val); + QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val); + void OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason); + void OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + void OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + + property Platform::String^ ServiceObjectPath + { + Platform::String^ get() { return m_ServiceObjectPath; } + void set(Platform::String^ value) { m_ServiceObjectPath = value; } + } + + property alljoyn_busobject BusObject + { + alljoyn_busobject get() { return m_busObject; } + void set(alljoyn_busobject value) { m_busObject = value; } + } + + property alljoyn_sessionportlistener SessionPortListener + { + alljoyn_sessionportlistener get() { return m_sessionPortListener; } + void set(alljoyn_sessionportlistener value) { m_sessionPortListener = value; } + } + + property alljoyn_sessionlistener SessionListener + { + alljoyn_sessionlistener get() { return m_sessionListener; } + void set(alljoyn_sessionlistener value) { m_sessionListener = value; } + } + + property alljoyn_sessionport SessionPort + { + alljoyn_sessionport get() { return m_sessionPort; } + internal: + void set(alljoyn_sessionport value) { m_sessionPort = value; } + } + + property alljoyn_sessionid SessionId + { + alljoyn_sessionid get() { return m_sessionId; } + } + + // Stop advertising the service and pass status to anyone listening for the Stopped event. + void StopInternal(int32 status); + + void BusAttachmentStateChanged(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ sender, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachmentStateChangedEventArgs^ args); + +private: + static void CallConcatenateHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + static void CallTextSentSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); + + // Register a callback function to handle methods. + QStatus AddMethodHandler(_In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_methodhandler_ptr handler); + // Register a callback function to handle incoming signals. + QStatus AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler); + + void UnregisterFromBus(); + + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; + SecureInterfaceSignals^ m_signals; + ISecureInterfaceService^ m_serviceInterface; + Platform::String^ m_ServiceObjectPath; + + alljoyn_busobject m_busObject; + alljoyn_sessionportlistener m_sessionPortListener; + alljoyn_sessionlistener m_sessionListener; + alljoyn_sessionport m_sessionPort; + alljoyn_sessionid m_sessionId; + + // Used to pass a pointer to this class to callbacks + Platform::WeakReference* m_weak; + + // These maps are required because we need a way to pass the producer to the method + // and signal handlers, but the current AllJoyn C API does not allow passing a context to these + // callbacks. + static std::map SourceObjects; + static std::map SourceInterfaces; +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp new file mode 100644 index 0000000000..e784c0ed05 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp @@ -0,0 +1,75 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Devices::AllJoyn; +using namespace com::microsoft::Samples::SecureInterface; + +// Note: Unlike an Interface implementation, which provides a single handler for each member, the event +// model allows for 0 or more listeners to be registered. The EventAdapter implementation deals with this +// difference by implementing a last-writer-wins policy. The lack of any return value (i.e., 0 listeners) +// is handled by returning a null result. + +// Methods +IAsyncOperation^ SecureInterfaceServiceEventAdapter::ConcatenateAsync(_In_ AllJoynMessageInfo^ info, _In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2) +{ + auto args = ref new SecureInterfaceConcatenateCalledEventArgs(info, interfaceMemberInStr1, interfaceMemberInStr2); + AllJoynHelpers::DispatchEvent([=]() { + ConcatenateCalled(this, args); + }); + return SecureInterfaceConcatenateCalledEventArgs::GetResultAsync(args); +} + +// Property Reads +IAsyncOperation^ SecureInterfaceServiceEventAdapter::GetIsUpperCaseEnabledAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + GetIsUpperCaseEnabledRequested(this, args); + }); + return SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::GetResultAsync(args); +} + +// Property Writes +IAsyncOperation^ SecureInterfaceServiceEventAdapter::SetIsUpperCaseEnabledAsync(_In_ AllJoynMessageInfo^ info, _In_ bool value) +{ + auto args = ref new SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs(info, value); + AllJoynHelpers::DispatchEvent([=]() { + SetIsUpperCaseEnabledRequested(this, args); + }); + return SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::GetResultAsync(args); +} + diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h new file mode 100644 index 0000000000..f7ea8ccf46 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h @@ -0,0 +1,59 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +// This class, and the associated EventArgs classes, exist for the benefit of JavaScript developers who +// do not have the ability to implement ISecureInterfaceService. Instead, SecureInterfaceServiceEventAdapter +// provides the Interface implementation and exposes a set of compatible events to the developer. +public ref class SecureInterfaceServiceEventAdapter sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceService +{ +public: + // Method Invocation Events + event Windows::Foundation::TypedEventHandler^ ConcatenateCalled; + + // Property Read Events + event Windows::Foundation::TypedEventHandler^ GetIsUpperCaseEnabledRequested; + + // Property Write Events + event Windows::Foundation::TypedEventHandler^ SetIsUpperCaseEnabledRequested; + + // ISecureInterfaceService Implementation + virtual Windows::Foundation::IAsyncOperation^ ConcatenateAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, _In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2); + + virtual Windows::Foundation::IAsyncOperation^ GetIsUpperCaseEnabledAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + virtual Windows::Foundation::IAsyncOperation^ SetIsUpperCaseEnabledAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, _In_ bool value); +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp new file mode 100644 index 0000000000..5f09fe837f --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp @@ -0,0 +1,277 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Devices::AllJoyn; +using namespace com::microsoft::Samples::SecureInterface; +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +// Methods +SecureInterfaceConcatenateCalledEventArgs::SecureInterfaceConcatenateCalledEventArgs( + _In_ AllJoynMessageInfo^ info, + _In_ Platform::String^ interfaceMemberInStr1, + _In_ Platform::String^ interfaceMemberInStr2) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info), + m_interfaceMemberInStr1(interfaceMemberInStr1), + m_interfaceMemberInStr2(interfaceMemberInStr2) +{ + m_result = SecureInterfaceConcatenateResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ SecureInterfaceConcatenateCalledEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &SecureInterfaceConcatenateCalledEventArgs::Complete); + return ref new Deferral(handler); +} + +void SecureInterfaceConcatenateCalledEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void SecureInterfaceConcatenateCalledEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void SecureInterfaceConcatenateCalledEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for ConcatenateCalled."); + } + else + { + m_tce.set(m_result); + } +} + +// Readable Properties +SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = SecureInterfaceGetIsUpperCaseEnabledResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::Complete); + return ref new Deferral(handler); +} + +void SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for GetIsUpperCaseEnabledRequested."); + } + else + { + m_tce.set(m_result); + } +} + +// Writable Properties +SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs( + _In_ AllJoynMessageInfo^ info, + _In_ bool value) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info), + m_value(value) +{ + m_result = SecureInterfaceSetIsUpperCaseEnabledResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::Complete); + return ref new Deferral(handler); +} + +void SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for SetIsUpperCaseEnabledRequested."); + } + else + { + m_tce.set(m_result); + } +} + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h new file mode 100644 index 0000000000..82476f6f47 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h @@ -0,0 +1,180 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +// Methods +public ref class SecureInterfaceConcatenateCalledEventArgs sealed +{ +public: + SecureInterfaceConcatenateCalledEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, _In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property SecureInterfaceConcatenateResult^ Result + { + SecureInterfaceConcatenateResult^ get() { return m_result; } + void set(_In_ SecureInterfaceConcatenateResult^ value) { m_result = value; } + } + + property Platform::String^ InStr1 + { + Platform::String^ get() { return m_interfaceMemberInStr1; } + } + + property Platform::String^ InStr2 + { + Platform::String^ get() { return m_interfaceMemberInStr2; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(SecureInterfaceConcatenateCalledEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + SecureInterfaceConcatenateResult^ m_result; + Platform::String^ m_interfaceMemberInStr1; + Platform::String^ m_interfaceMemberInStr2; +}; + +// Readable Properties +public ref class SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs sealed +{ +public: + SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property SecureInterfaceGetIsUpperCaseEnabledResult^ Result + { + SecureInterfaceGetIsUpperCaseEnabledResult^ get() { return m_result; } + void set(_In_ SecureInterfaceGetIsUpperCaseEnabledResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + SecureInterfaceGetIsUpperCaseEnabledResult^ m_result; +}; + +// Writable Properties +public ref class SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs sealed +{ +public: + SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, _In_ bool value); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property bool Value + { + bool get() { return m_value; } + } + + property SecureInterfaceSetIsUpperCaseEnabledResult^ Result + { + SecureInterfaceSetIsUpperCaseEnabledResult^ get() { return m_result; } + void set(_In_ SecureInterfaceSetIsUpperCaseEnabledResult^ value) { m_result = value; } + } + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + + Windows::Foundation::Deferral^ GetDeferral(); + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + bool m_value; + SecureInterfaceSetIsUpperCaseEnabledResult^ m_result; +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp new file mode 100644 index 0000000000..d21b092fde --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp @@ -0,0 +1,80 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Devices::AllJoyn; +using namespace Windows::Foundation; +using namespace com::microsoft::Samples::SecureInterface; + +void SecureInterfaceSignals::Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId) +{ + m_busObject = busObject; + m_sessionId = sessionId; + + auto interfaceDefinition = alljoyn_busattachment_getinterface(alljoyn_busobject_getbusattachment(busObject), "com.microsoft.Samples.SecureInterface"); + alljoyn_interfacedescription_getmember(interfaceDefinition, "TextSent", &m_memberTextSent); +} + +void SecureInterfaceSignals::TextSent(_In_ Platform::String^ interfaceMemberMessage) +{ + if (nullptr == m_busObject) + { + return; + } + + size_t argCount = 1; + alljoyn_msgarg arguments = alljoyn_msgarg_array_create(argCount); + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(arguments, 0), "s", interfaceMemberMessage); + + alljoyn_busobject_signal( + m_busObject, + NULL, // Generated code only supports broadcast signals. + m_sessionId, + m_memberTextSent, + arguments, + argCount, + 0, // A signal with a TTL of 0 will be sent to every member of the session, regardless of how long it takes to deliver the message + ALLJOYN_MESSAGE_FLAG_GLOBAL_BROADCAST, // Broadcast to everyone in the session. + NULL); // The generated code does not need the generated signal message + + alljoyn_msgarg_destroy(arguments); +} + +void SecureInterfaceSignals::CallTextSentReceived(_In_ SecureInterfaceSignals^ sender, _In_ SecureInterfaceTextSentReceivedEventArgs^ args) +{ + AllJoynHelpers::DispatchEvent([=]() { + TextSentReceived(sender, args); + }); +} + diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.h new file mode 100644 index 0000000000..71abc5428e --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +ref class SecureInterfaceSignals; + +public interface class ISecureInterfaceSignals +{ + event Windows::Foundation::TypedEventHandler^ TextSentReceived; +}; + +public ref class SecureInterfaceSignals sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceSignals +{ +public: + // Calling this method will send the TextSent signal to every member of the session. + void TextSent(_In_ Platform::String^ interfaceMemberMessage); + + // This event fires whenever the TextSent signal is sent by another member of the session. + virtual event Windows::Foundation::TypedEventHandler^ TextSentReceived; + +internal: + void Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId); + void CallTextSentReceived(_In_ SecureInterfaceSignals^ sender, _In_ SecureInterfaceTextSentReceivedEventArgs^ args); + +private: + alljoyn_busobject m_busObject; + alljoyn_sessionid m_sessionId; + + alljoyn_interfacedescription_member m_memberTextSent; +}; + +} } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceStructures.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceStructures.h new file mode 100644 index 0000000000..d988bcbfbf --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceStructures.h @@ -0,0 +1,119 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +public ref class AllJoynMessageArgStructure sealed : Windows::Foundation::Collections::IVector +{ +public: + AllJoynMessageArgStructure() + { + m_vector = ref new Platform::Collections::Vector(); + } + + virtual Windows::Foundation::Collections::IIterator^ First() + { + return m_vector->First(); + } + + virtual Platform::Object^ GetAt(unsigned int index) + { + return m_vector->GetAt(index); + } + + virtual property unsigned int Size { + virtual unsigned int get() + { + return m_vector->Size; + } + } + + virtual bool IndexOf(Platform::Object^ value, unsigned int * index) + { + return m_vector->IndexOf(value, index); + } + + virtual unsigned int GetMany(unsigned int startIndex, Platform::WriteOnlyArray^ items) + { + return m_vector->GetMany(startIndex, items); + } + + virtual Windows::Foundation::Collections::IVectorView^ GetView() + { + return m_vector->GetView(); + } + + virtual void SetAt(unsigned int index, Platform::Object^ item) + { + return m_vector->SetAt(index, item); + } + + virtual void InsertAt(unsigned int index, Platform::Object^ item) + { + return m_vector->InsertAt(index, item); + } + + virtual void Append(Platform::Object^ item) + { + return m_vector->Append(item); + } + + virtual void RemoveAt(unsigned int index) + { + return m_vector->RemoveAt(index); + } + + virtual void RemoveAtEnd() + { + return m_vector->RemoveAtEnd(); + } + + virtual void Clear() + { + return m_vector->Clear(); + } + + virtual void ReplaceAll(const Platform::Array^ arr) + { + return m_vector->ReplaceAll(arr); + } + +private: + Platform::Collections::Vector^ m_vector; +}; +} } } } + +partial ref class TypeConversionHelpers +{ +internal: +}; diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.cpp new file mode 100644 index 0000000000..3261adc15e --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.cpp @@ -0,0 +1,153 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Devices::AllJoyn; +using namespace com::microsoft::Samples::SecureInterface; + +SecureInterfaceWatcher::SecureInterfaceWatcher(AllJoynBusAttachment^ busAttachment) : + m_aboutListener(nullptr) +{ + m_busAttachment = busAttachment; + m_weak = new WeakReference(this); + m_busAttachmentStateChangedToken.Value = 0; +} + +SecureInterfaceWatcher::~SecureInterfaceWatcher() +{ + UnregisterFromBus(); +} + +void SecureInterfaceWatcher::UnregisterFromBus() +{ + if (nullptr != m_aboutListener) + { + PCSTR interfaces[] = { "com.microsoft.Samples.SecureInterface" }; + alljoyn_busattachment_cancelwhoimplements_interfaces( + AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), + interfaces, + _countof(interfaces)); + + alljoyn_busattachment_unregisteraboutlistener(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), m_aboutListener); + alljoyn_aboutlistener_destroy(m_aboutListener); + m_aboutListener = nullptr; + } + if ((nullptr != m_busAttachment) && (0 != m_busAttachmentStateChangedToken.Value)) + { + m_busAttachment->StateChanged -= m_busAttachmentStateChangedToken; + } +} + +void SecureInterfaceWatcher::OnAnnounce( + _In_ PCSTR name, + _In_ uint16_t version, + _In_ alljoyn_sessionport port, + _In_ alljoyn_msgarg objectDescriptionArg, + _In_ const alljoyn_msgarg aboutDataArg) +{ + UNREFERENCED_PARAMETER(version); + UNREFERENCED_PARAMETER(aboutDataArg); + + alljoyn_aboutobjectdescription objectDescription = alljoyn_aboutobjectdescription_create_full(objectDescriptionArg); + + if (alljoyn_aboutobjectdescription_hasinterface(objectDescription, "com.microsoft.Samples.SecureInterface")) + { + AllJoynServiceInfo^ args = ref new AllJoynServiceInfo( + AllJoynHelpers::MultibyteToPlatformString(name), + AllJoynHelpers::GetObjectPath(objectDescription, "com.microsoft.Samples.SecureInterface"), + port); + Added(this, args); + } + alljoyn_aboutobjectdescription_destroy(objectDescription); +} + +void SecureInterfaceWatcher::BusAttachmentStateChanged(_In_ AllJoynBusAttachment^ sender, _In_ AllJoynBusAttachmentStateChangedEventArgs^ args) +{ + if (args->State == AllJoynBusAttachmentState::Connected) + { + alljoyn_aboutlistener_callback callbacks = + { + AllJoynHelpers::AnnounceHandler + }; + m_aboutListener = alljoyn_aboutlistener_create(&callbacks, m_weak); + + alljoyn_busattachment_registeraboutlistener(AllJoynHelpers::GetInternalBusAttachment(sender), m_aboutListener); + PCSTR interfaces[] = { "com.microsoft.Samples.SecureInterface" }; + + auto status = alljoyn_busattachment_whoimplements_interfaces( + AllJoynHelpers::GetInternalBusAttachment(sender), + interfaces, + _countof(interfaces)); + if (ER_OK != status) + { + StopInternal(status); + } + } + else if (args->State == AllJoynBusAttachmentState::Disconnected) + { + StopInternal(ER_BUS_STOPPING); + } +} + +void SecureInterfaceWatcher::Start() +{ + if (nullptr == m_busAttachment) + { + StopInternal(ER_FAIL); + return; + } + + int32 result = AllJoynHelpers::CreateInterfaces(m_busAttachment, c_SecureInterfaceIntrospectionXml); + if (result != AllJoynStatus::Ok) + { + StopInternal(result); + return; + } + + m_busAttachmentStateChangedToken = m_busAttachment->StateChanged += ref new TypedEventHandler(this, &SecureInterfaceWatcher::BusAttachmentStateChanged); + m_busAttachment->Connect(); +} + +void SecureInterfaceWatcher::Stop() +{ + StopInternal(AllJoynStatus::Ok); +} + +void SecureInterfaceWatcher::StopInternal(int32 status) +{ + UnregisterFromBus(); + Stopped(this, ref new AllJoynProducerStoppedEventArgs(status)); +} \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.h new file mode 100644 index 0000000000..80aff081f6 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.h @@ -0,0 +1,97 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +ref class SecureInterfaceWatcher; + +public interface class ISecureInterfaceWatcher +{ + event Windows::Foundation::TypedEventHandler^ Added; + event Windows::Foundation::TypedEventHandler^ Stopped; +}; + +public ref class SecureInterfaceWatcher sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceWatcher +{ +public: + SecureInterfaceWatcher(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + virtual ~SecureInterfaceWatcher(); + + // This event will fire whenever a producer for this service is found. + virtual event Windows::Foundation::TypedEventHandler^ Added; + + // This event will fire whenever the watcher is stopped. + virtual event Windows::Foundation::TypedEventHandler^ Stopped; + + // Start watching for producers advertising this service. + void Start(); + + // Stop watching for producers for this service. + void Stop(); + +internal: + void OnAnnounce( + _In_ PCSTR name, + _In_ uint16_t version, + _In_ alljoyn_sessionport port, + _In_ alljoyn_msgarg objectDescriptionArg, + _In_ const alljoyn_msgarg aboutDataArg); + + void OnPropertyChanged(_In_ PCSTR prop_name, _In_ alljoyn_msgarg prop_value) + { + UNREFERENCED_PARAMETER(prop_name); UNREFERENCED_PARAMETER(prop_value); + } + + property Windows::Devices::AllJoyn::AllJoynBusAttachment^ BusAttachment + { + Windows::Devices::AllJoyn::AllJoynBusAttachment^ get() { return m_busAttachment; } + } + + // Stop watching for producers advertising this service and pass status to anyone listening for the Stopped event. + void StopInternal(int32 status); + + void BusAttachmentStateChanged(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ sender, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachmentStateChangedEventArgs^ args); + +private: + void UnregisterFromBus(); + + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; + + alljoyn_aboutlistener m_aboutListener; + + // Used to pass a pointer to this class to callbacks. + Platform::WeakReference* m_weak; +}; + +} } } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.cpp new file mode 100644 index 0000000000..4b23b663b1 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.cpp @@ -0,0 +1,32 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.h new file mode 100644 index 0000000000..4fbebeac1d --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.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. +// +//********************************************************* + +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "AllJoynHelpers.h" +#include "AllJoynBusObjectManager.h" + +#define PROJECT_NAMESPACE com::microsoft::Samples::SecureInterface + +#include "SecureInterfaceStructures.h" +#include "TypeConversionHelpers.h" +#include "SecureInterfaceMethodResults.h" +#include "SecureInterfaceEventArgs.h" +#include "ISecureInterfaceService.h" +#include "SecureInterfaceSignals.h" +#include "SecureInterfaceProducer.h" +#include "SecureInterfaceWatcher.h" +#include "SecureInterfaceConsumer.h" +#include "SecureInterfaceServiceEventArgs.h" +#include "SecureInterfaceServiceEventAdapter.h" \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h new file mode 100644 index 0000000000..70419c155a --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h @@ -0,0 +1,68 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +public interface class IOnboardingService +{ +public: + // Implement this function to handle calls to the ConfigureWiFi method. + Windows::Foundation::IAsyncOperation^ ConfigureWiFiAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info , _In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType); + + // Implement this function to handle calls to the Connect method. + Windows::Foundation::IAsyncOperation^ ConnectAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info ); + + // Implement this function to handle calls to the Offboard method. + Windows::Foundation::IAsyncOperation^ OffboardAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info ); + + // Implement this function to handle calls to the GetScanInfo method. + Windows::Foundation::IAsyncOperation^ GetScanInfoAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info ); + + // Implement this function to handle requests for the value of the Version property. + // + // Currently, info will always be null, because no information is available about the requestor. + Windows::Foundation::IAsyncOperation^ GetVersionAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + // Implement this function to handle requests for the value of the State property. + // + // Currently, info will always be null, because no information is available about the requestor. + Windows::Foundation::IAsyncOperation^ GetStateAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + // Implement this function to handle requests for the value of the LastError property. + // + // Currently, info will always be null, because no information is available about the requestor. + Windows::Foundation::IAsyncOperation^ GetLastErrorAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + +}; + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp new file mode 100644 index 0000000000..41ce62edae --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp @@ -0,0 +1,536 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Devices::AllJoyn; +using namespace org::alljoyn::Onboarding; + +std::map OnboardingConsumer::SourceInterfaces; + +OnboardingConsumer::OnboardingConsumer(AllJoynBusAttachment^ busAttachment) + : m_busAttachment(busAttachment), + m_proxyBusObject(nullptr), + m_busObject(nullptr), + m_sessionListener(nullptr), + m_sessionId(0) +{ + m_weak = new WeakReference(this); + m_signals = ref new OnboardingSignals(); + m_nativeBusAttachment = AllJoynHelpers::GetInternalBusAttachment(m_busAttachment); +} + +OnboardingConsumer::~OnboardingConsumer() +{ + AllJoynBusObjectManager::ReleaseBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data()); + if (SessionListener != nullptr) + { + alljoyn_busattachment_setsessionlistener(m_nativeBusAttachment, m_sessionId, nullptr); + alljoyn_sessionlistener_destroy(SessionListener); + } + if (nullptr != ProxyBusObject) + { + alljoyn_proxybusobject_destroy(ProxyBusObject); + } + delete m_weak; +} + +void OnboardingConsumer::OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) +{ + if (sessionId == m_sessionId) + { + AllJoynSessionLostEventArgs^ args = ref new AllJoynSessionLostEventArgs(static_cast(reason)); + SessionLost(this, args); + } +} + +void OnboardingConsumer::OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberAddedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + SessionMemberAdded(this, args); + } +} + +void OnboardingConsumer::OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberRemovedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + SessionMemberRemoved(this, args); + } +} + +QStatus OnboardingConsumer::AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler) +{ + alljoyn_interfacedescription_member member; + if (!alljoyn_interfacedescription_getmember(interfaceDescription, methodName, &member)) + { + return ER_BUS_INTERFACE_NO_SUCH_MEMBER; + } + + return alljoyn_busattachment_registersignalhandler(busAttachment, handler, member, NULL); +} + +IAsyncOperation^ OnboardingConsumer::JoinSessionAsync( + _In_ AllJoynServiceInfo^ serviceInfo, _Inout_ OnboardingWatcher^ watcher) +{ + return create_async([serviceInfo, watcher]() -> OnboardingJoinSessionResult^ + { + auto result = ref new OnboardingJoinSessionResult(); + result->Status = AllJoynStatus::Ok; + result->Consumer = nullptr; + + result->Consumer = ref new OnboardingConsumer(watcher->BusAttachment); + result->Status = result->Consumer->JoinSession(serviceInfo); + + return result; + }); +} + +IAsyncOperation^ OnboardingConsumer::ConfigureWiFiAsync(_In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType) +{ + return create_async([this, interfaceMemberSSID, interfaceMemberPassphrase, interfaceMemberAuthType]() -> OnboardingConfigureWiFiResult^ + { + auto result = ref new OnboardingConfigureWiFiResult(); + + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); + size_t argCount = 3; + alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); + + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 0), "s", interfaceMemberSSID); + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 1), "s", interfaceMemberPassphrase); + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 2), "n", interfaceMemberAuthType); + + QStatus status = alljoyn_proxybusobject_methodcall( + ProxyBusObject, + "org.alljoyn.Onboarding", + "ConfigureWiFi", + inputs, + argCount, + message, + c_MessageTimeoutInMilliseconds, + 0); + result->Status = static_cast(status); + if (ER_OK == status) + { + result->Status = AllJoynStatus::Ok; + int16 argument0; + status = static_cast(TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "n", &argument0)); + result->Status2 = argument0; + + if (status != ER_OK) + { + result->Status = static_cast(status); + } + } + else if (ER_BUS_REPLY_IS_ERROR_MESSAGE == status) + { + alljoyn_msgarg errorArg = alljoyn_message_getarg(message, 1); + if (nullptr != errorArg) + { + uint16 errorStatus; + status = alljoyn_msgarg_get_uint16(errorArg, &errorStatus); + if (ER_OK == status) + { + status = static_cast(errorStatus); + } + } + result->Status = static_cast(status); + } + + alljoyn_message_destroy(message); + alljoyn_msgarg_destroy(inputs); + + return result; + }); +} +IAsyncOperation^ OnboardingConsumer::ConnectAsync() +{ + return create_async([this]() -> OnboardingConnectResult^ + { + auto result = ref new OnboardingConnectResult(); + + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); + size_t argCount = 0; + alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); + + + QStatus status = alljoyn_proxybusobject_methodcall( + ProxyBusObject, + "org.alljoyn.Onboarding", + "Connect", + inputs, + argCount, + message, + c_MessageTimeoutInMilliseconds, + 0); + result->Status = static_cast(status); + + alljoyn_message_destroy(message); + alljoyn_msgarg_destroy(inputs); + + return result; + }); +} +IAsyncOperation^ OnboardingConsumer::OffboardAsync() +{ + return create_async([this]() -> OnboardingOffboardResult^ + { + auto result = ref new OnboardingOffboardResult(); + + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); + size_t argCount = 0; + alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); + + + QStatus status = alljoyn_proxybusobject_methodcall( + ProxyBusObject, + "org.alljoyn.Onboarding", + "Offboard", + inputs, + argCount, + message, + c_MessageTimeoutInMilliseconds, + 0); + result->Status = static_cast(status); + + alljoyn_message_destroy(message); + alljoyn_msgarg_destroy(inputs); + + return result; + }); +} +IAsyncOperation^ OnboardingConsumer::GetScanInfoAsync() +{ + return create_async([this]() -> OnboardingGetScanInfoResult^ + { + auto result = ref new OnboardingGetScanInfoResult(); + + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); + size_t argCount = 0; + alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); + + + QStatus status = alljoyn_proxybusobject_methodcall( + ProxyBusObject, + "org.alljoyn.Onboarding", + "GetScanInfo", + inputs, + argCount, + message, + c_MessageTimeoutInMilliseconds, + 0); + result->Status = static_cast(status); + if (ER_OK == status) + { + result->Status = AllJoynStatus::Ok; + uint16 argument0; + status = static_cast(TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "q", &argument0)); + result->Age = argument0; + + if (status != ER_OK) + { + result->Status = static_cast(status); + } + Windows::Foundation::Collections::IVector^ argument1; + status = static_cast(TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 1), "a(sn)", &argument1)); + result->ScanList = argument1; + + if (status != ER_OK) + { + result->Status = static_cast(status); + } + } + else if (ER_BUS_REPLY_IS_ERROR_MESSAGE == status) + { + alljoyn_msgarg errorArg = alljoyn_message_getarg(message, 1); + if (nullptr != errorArg) + { + uint16 errorStatus; + status = alljoyn_msgarg_get_uint16(errorArg, &errorStatus); + if (ER_OK == status) + { + status = static_cast(errorStatus); + } + } + result->Status = static_cast(status); + } + + alljoyn_message_destroy(message); + alljoyn_msgarg_destroy(inputs); + + return result; + }); +} + +IAsyncOperation^ OnboardingConsumer::GetVersionAsync() +{ + return create_async([this]() -> OnboardingGetVersionResult^ + { + PropertyGetContext getContext; + + alljoyn_proxybusobject_getpropertyasync( + ProxyBusObject, + "org.alljoyn.Onboarding", + "Version", + [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) + { + UNREFERENCED_PARAMETER(obj); + auto propertyContext = static_cast*>(context); + + if (ER_OK == status) + { + uint16 argument; + TypeConversionHelpers::GetAllJoynMessageArg(value, "q", &argument); + + propertyContext->SetValue(argument); + } + propertyContext->SetStatus(status); + propertyContext->SetEvent(); + }, + c_MessageTimeoutInMilliseconds, + &getContext); + + getContext.Wait(); + + auto result = ref new OnboardingGetVersionResult(); + result->Status = getContext.GetStatus(); + result->Version = getContext.GetValue(); + return result; + }); +} + +IAsyncOperation^ OnboardingConsumer::GetStateAsync() +{ + return create_async([this]() -> OnboardingGetStateResult^ + { + PropertyGetContext getContext; + + alljoyn_proxybusobject_getpropertyasync( + ProxyBusObject, + "org.alljoyn.Onboarding", + "State", + [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) + { + UNREFERENCED_PARAMETER(obj); + auto propertyContext = static_cast*>(context); + + if (ER_OK == status) + { + int16 argument; + TypeConversionHelpers::GetAllJoynMessageArg(value, "n", &argument); + + propertyContext->SetValue(argument); + } + propertyContext->SetStatus(status); + propertyContext->SetEvent(); + }, + c_MessageTimeoutInMilliseconds, + &getContext); + + getContext.Wait(); + + auto result = ref new OnboardingGetStateResult(); + result->Status = getContext.GetStatus(); + result->State = getContext.GetValue(); + return result; + }); +} + +IAsyncOperation^ OnboardingConsumer::GetLastErrorAsync() +{ + return create_async([this]() -> OnboardingGetLastErrorResult^ + { + PropertyGetContext getContext; + + alljoyn_proxybusobject_getpropertyasync( + ProxyBusObject, + "org.alljoyn.Onboarding", + "LastError", + [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) + { + UNREFERENCED_PARAMETER(obj); + auto propertyContext = static_cast*>(context); + + if (ER_OK == status) + { + OnboardingLastError^ argument; + TypeConversionHelpers::GetAllJoynMessageArg(value, "(ns)", &argument); + + propertyContext->SetValue(argument); + } + propertyContext->SetStatus(status); + propertyContext->SetEvent(); + }, + c_MessageTimeoutInMilliseconds, + &getContext); + + getContext.Wait(); + + auto result = ref new OnboardingGetLastErrorResult(); + result->Status = getContext.GetStatus(); + result->LastError = getContext.GetValue(); + return result; + }); +} + +void OnboardingConsumer::OnPropertyChanged(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated) +{ + UNREFERENCED_PARAMETER(obj); + UNREFERENCED_PARAMETER(interfaceName); + UNREFERENCED_PARAMETER(changed); + UNREFERENCED_PARAMETER(invalidated); +} + +void OnboardingConsumer::CallConnectionResultSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message) +{ + auto source = SourceInterfaces.find(member->iface); + if (source == SourceInterfaces.end()) + { + return; + } + + auto consumer = source->second->Resolve(); + if (consumer->Signals != nullptr) + { + auto callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + auto eventArgs = ref new OnboardingConnectionResultReceivedEventArgs(); + eventArgs->MessageInfo = callInfo; + + Onboarding^ argument0; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "(ns)", &argument0); + + eventArgs->Arg = argument0; + + consumer->Signals->CallConnectionResultReceived(consumer->Signals, eventArgs); + } +} + +int32 OnboardingConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) +{ + alljoyn_sessionlistener_callbacks callbacks = + { + AllJoynHelpers::SessionLostHandler, + AllJoynHelpers::SessionMemberAddedHandler, + AllJoynHelpers::SessionMemberRemovedHandler + }; + + alljoyn_busattachment_enableconcurrentcallbacks(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment)); + + SessionListener = alljoyn_sessionlistener_create(&callbacks, m_weak); + alljoyn_sessionopts sessionOpts = alljoyn_sessionopts_create(ALLJOYN_TRAFFIC_TYPE_MESSAGES, true, ALLJOYN_PROXIMITY_ANY, ALLJOYN_TRANSPORT_ANY); + + std::vector sessionNameUtf8 = AllJoynHelpers::PlatformToMultibyteString(serviceInfo->UniqueName); + RETURN_IF_QSTATUS_ERROR(alljoyn_busattachment_joinsession( + m_nativeBusAttachment, + &sessionNameUtf8[0], + serviceInfo->SessionPort, + SessionListener, + &m_sessionId, + sessionOpts)); + alljoyn_sessionopts_destroy(sessionOpts); + + ServiceObjectPath = serviceInfo->ObjectPath; + std::vector objectPath = AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath); + + if (objectPath.empty()) + { + return AllJoynStatus::Fail; + } + + ProxyBusObject = alljoyn_proxybusobject_create(m_nativeBusAttachment, &sessionNameUtf8[0], &objectPath[0], m_sessionId); + if (nullptr == ProxyBusObject) + { + return AllJoynStatus::Fail; + } + + + alljoyn_interfacedescription description = alljoyn_busattachment_getinterface(m_nativeBusAttachment, "org.alljoyn.Onboarding"); + if (nullptr == description) + { + return AllJoynStatus::Fail; + } + + unsigned int noneMechanismIndex = 0; + bool authenticationMechanismsContainsNone = m_busAttachment->AuthenticationMechanisms->IndexOf(AllJoynAuthenticationMechanism::None, &noneMechanismIndex); + QCC_BOOL interfaceIsSecure = alljoyn_interfacedescription_issecure(description); + + // If the current set of AuthenticationMechanisms supports authentication, + // determine whether to secure the connection. + if (AllJoynHelpers::CanSecure(m_busAttachment->AuthenticationMechanisms)) + { + // Secure the connection if the org.alljoyn.Bus.Secure XML annotation + // is specified, or if None is not present in AuthenticationMechanisms. + if (!authenticationMechanismsContainsNone || interfaceIsSecure) + { + alljoyn_proxybusobject_secureconnection(ProxyBusObject, QCC_FALSE); + } + } + else + { + // If the current set of AuthenticationMechanisms does not support authentication + // but the interface requires security, report an error. + if (interfaceIsSecure) + { + return static_cast(ER_BUS_NO_AUTHENTICATION_MECHANISM); + } + } + + RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::GetBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data(), &m_busObject)); + RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_addinterface(ProxyBusObject, description)); + + if (!AllJoynBusObjectManager::BusObjectIsRegistered(m_nativeBusAttachment, m_busObject)) + { + RETURN_IF_QSTATUS_ERROR(alljoyn_busobject_addinterface(BusObject, description)); + } + + QStatus result = AddSignalHandler( + m_nativeBusAttachment, + description, + "ConnectionResult", + [](const alljoyn_interfacedescription_member* member, PCSTR srcPath, alljoyn_message message) { UNREFERENCED_PARAMETER(srcPath); CallConnectionResultSignalHandler(member, message); }); + if (result != ER_OK) + { + return static_cast(result); + } + + SourceInterfaces[description] = m_weak; + RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, true)); + m_signals->Initialize(BusObject, m_sessionId); + + return AllJoynStatus::Ok; +} diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.h new file mode 100644 index 0000000000..abcfb9a75a --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +public interface class IOnboardingConsumer +{ + event Windows::Foundation::TypedEventHandler^ SessionLost; + event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; +}; + +public ref class OnboardingConsumer sealed : [Windows::Foundation::Metadata::Default] IOnboardingConsumer +{ +public: + OnboardingConsumer(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + virtual ~OnboardingConsumer(); + + // Join the AllJoyn session specified by sessionName. + // + // This will usually be called after the unique name of a producer has been reported + // in the Added callback on the Watcher. + static Windows::Foundation::IAsyncOperation^ JoinSessionAsync(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo, _Inout_ OnboardingWatcher^ watcher); + + // Call the ConfigureWiFi method + Windows::Foundation::IAsyncOperation^ ConfigureWiFiAsync(_In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType); + // Call the Connect method + Windows::Foundation::IAsyncOperation^ ConnectAsync(); + // Call the Offboard method + Windows::Foundation::IAsyncOperation^ OffboardAsync(); + // Call the GetScanInfo method + Windows::Foundation::IAsyncOperation^ GetScanInfoAsync(); + // Get the value of the Version property. + Windows::Foundation::IAsyncOperation^ GetVersionAsync(); + + // Get the value of the State property. + Windows::Foundation::IAsyncOperation^ GetStateAsync(); + + // Get the value of the LastError property. + Windows::Foundation::IAsyncOperation^ GetLastErrorAsync(); + + + // Used to send signals or register functions to handle received signals. + property OnboardingSignals^ Signals + { + OnboardingSignals^ get() { return m_signals; } + } + + // This event will fire whenever the consumer loses the session that it is a member of. + virtual event Windows::Foundation::TypedEventHandler^ SessionLost; + + // This event will fire whenever a member joins the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + + // This event will fire whenever a member leaves the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; + +internal: + // Consumers do not support property get. + QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val) + { + UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); + return ER_NOT_IMPLEMENTED; + } + + // Consumers do not support property set. + QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val) + { + UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); + return ER_NOT_IMPLEMENTED; + } + + void OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason); + void OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + void OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + + void OnPropertyChanged(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated); + + property Platform::String^ ServiceObjectPath + { + Platform::String^ get() { return m_ServiceObjectPath; } + void set(Platform::String^ value) { m_ServiceObjectPath = value; } + } + + property alljoyn_proxybusobject ProxyBusObject + { + alljoyn_proxybusobject get() { return m_proxyBusObject; } + void set(alljoyn_proxybusobject value) { m_proxyBusObject = value; } + } + + property alljoyn_busobject BusObject + { + alljoyn_busobject get() { return m_busObject; } + void set(alljoyn_busobject value) { m_busObject = value; } + } + + property alljoyn_sessionlistener SessionListener + { + alljoyn_sessionlistener get() { return m_sessionListener; } + void set(alljoyn_sessionlistener value) { m_sessionListener = value; } + } + + property alljoyn_sessionid SessionId + { + alljoyn_sessionid get() { return m_sessionId; } + } + +private: + int32 JoinSession(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo); + + // Register a callback function to handle incoming signals. + QStatus AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler); + + static void CallConnectionResultSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); + + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + OnboardingSignals^ m_signals; + Platform::String^ m_ServiceObjectPath; + + alljoyn_proxybusobject m_proxyBusObject; + alljoyn_busobject m_busObject; + alljoyn_sessionlistener m_sessionListener; + alljoyn_sessionid m_sessionId; + alljoyn_busattachment m_nativeBusAttachment; + + // Used to pass a pointer to this class to callbacks + Platform::WeakReference* m_weak; + + // This map is required because we need a way to pass the consumer to the signal + // handlers, but the current AllJoyn C API does not allow passing a context to these + // callbacks. + static std::map SourceInterfaces; +}; + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h new file mode 100644 index 0000000000..58bf609018 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h @@ -0,0 +1,60 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +// Signals +public ref class OnboardingConnectionResultReceivedEventArgs sealed +{ +public: + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + void set(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ value) { m_messageInfo = value; } + } + + property Onboarding^ Arg + { + Onboarding^ get() { return m_interfaceMemberArg; } + internal: + void set(_In_ Onboarding^ value) { m_interfaceMemberArg = value; } + } + +private: + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + + Onboarding^ m_interfaceMemberArg; +}; + + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h new file mode 100644 index 0000000000..4b710c1bc5 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h @@ -0,0 +1,311 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +ref class OnboardingConsumer; + +public ref class OnboardingConfigureWiFiResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property int16 Status2 + { + int16 get() { return m_interfaceMemberStatus2; } + internal: + void set(_In_ int16 value) { m_interfaceMemberStatus2 = value; } + } + + static OnboardingConfigureWiFiResult^ CreateSuccessResult(_In_ int16 interfaceMemberStatus2) + { + auto result = ref new OnboardingConfigureWiFiResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->Status2 = interfaceMemberStatus2; + return result; + } + + static OnboardingConfigureWiFiResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingConfigureWiFiResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + int16 m_interfaceMemberStatus2; +}; + +public ref class OnboardingConnectResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + + static OnboardingConnectResult^ CreateSuccessResult() + { + auto result = ref new OnboardingConnectResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + return result; + } + + static OnboardingConnectResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingConnectResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; +}; + +public ref class OnboardingOffboardResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + + static OnboardingOffboardResult^ CreateSuccessResult() + { + auto result = ref new OnboardingOffboardResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + return result; + } + + static OnboardingOffboardResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingOffboardResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; +}; + +public ref class OnboardingGetScanInfoResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property uint16 Age + { + uint16 get() { return m_interfaceMemberAge; } + internal: + void set(_In_ uint16 value) { m_interfaceMemberAge = value; } + } + property Windows::Foundation::Collections::IVector^ ScanList + { + Windows::Foundation::Collections::IVector^ get() { return m_interfaceMemberScanList; } + internal: + void set(_In_ Windows::Foundation::Collections::IVector^ value) { m_interfaceMemberScanList = value; } + } + + static OnboardingGetScanInfoResult^ CreateSuccessResult(_In_ uint16 interfaceMemberAge, _In_ Windows::Foundation::Collections::IVector^ interfaceMemberScanList) + { + auto result = ref new OnboardingGetScanInfoResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->Age = interfaceMemberAge; + result->ScanList = interfaceMemberScanList; + return result; + } + + static OnboardingGetScanInfoResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingGetScanInfoResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + uint16 m_interfaceMemberAge; + Windows::Foundation::Collections::IVector^ m_interfaceMemberScanList; +}; + +public ref class OnboardingJoinSessionResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property OnboardingConsumer^ Consumer + { + OnboardingConsumer^ get() { return m_consumer; } + internal: + void set(_In_ OnboardingConsumer^ value) { m_consumer = value; } + }; + +private: + int32 m_status; + OnboardingConsumer^ m_consumer; +}; + +public ref class OnboardingGetVersionResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property uint16 Version + { + uint16 get() { return m_value; } + internal: + void set(_In_ uint16 value) { m_value = value; } + } + + static OnboardingGetVersionResult^ CreateSuccessResult(_In_ uint16 value) + { + auto result = ref new OnboardingGetVersionResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->Version = value; + return result; + } + + static OnboardingGetVersionResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingGetVersionResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + uint16 m_value; +}; + +public ref class OnboardingGetStateResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property int16 State + { + int16 get() { return m_value; } + internal: + void set(_In_ int16 value) { m_value = value; } + } + + static OnboardingGetStateResult^ CreateSuccessResult(_In_ int16 value) + { + auto result = ref new OnboardingGetStateResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->State = value; + return result; + } + + static OnboardingGetStateResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingGetStateResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + int16 m_value; +}; + +public ref class OnboardingGetLastErrorResult sealed +{ +public: + property int32 Status + { + int32 get() { return m_status; } + internal: + void set(_In_ int32 value) { m_status = value; } + } + + property OnboardingLastError^ LastError + { + OnboardingLastError^ get() { return m_value; } + internal: + void set(_In_ OnboardingLastError^ value) { m_value = value; } + } + + static OnboardingGetLastErrorResult^ CreateSuccessResult(_In_ OnboardingLastError^ value) + { + auto result = ref new OnboardingGetLastErrorResult(); + result->Status = Windows::Devices::AllJoyn::AllJoynStatus::Ok; + result->LastError = value; + return result; + } + + static OnboardingGetLastErrorResult^ CreateFailureResult(_In_ int32 status) + { + auto result = ref new OnboardingGetLastErrorResult(); + result->Status = status; + return result; + } + +private: + int32 m_status; + OnboardingLastError^ m_value; +}; + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp new file mode 100644 index 0000000000..4846c7e0be --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp @@ -0,0 +1,643 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Devices::AllJoyn; +using namespace org::alljoyn::Onboarding; + +std::map OnboardingProducer::SourceObjects; +std::map OnboardingProducer::SourceInterfaces; + +OnboardingProducer::OnboardingProducer(AllJoynBusAttachment^ busAttachment) + : m_busAttachment(busAttachment), + m_sessionListener(nullptr), + m_busObject(nullptr), + m_sessionPort(0), + m_sessionId(0) +{ + m_weak = new WeakReference(this); + ServiceObjectPath = ref new String(L"/Service"); + m_signals = ref new OnboardingSignals(); + m_busAttachmentStateChangedToken.Value = 0; +} + +OnboardingProducer::~OnboardingProducer() +{ + UnregisterFromBus(); + delete m_weak; +} + +void OnboardingProducer::UnregisterFromBus() +{ + if ((nullptr != m_busAttachment) && (0 != m_busAttachmentStateChangedToken.Value)) + { + m_busAttachment->StateChanged -= m_busAttachmentStateChangedToken; + m_busAttachmentStateChangedToken.Value = 0; + } + if (nullptr != SessionPortListener) + { + alljoyn_busattachment_unbindsessionport(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), m_sessionPort); + alljoyn_sessionportlistener_destroy(SessionPortListener); + SessionPortListener = nullptr; + } + if (nullptr != BusObject) + { + alljoyn_busattachment_unregisterbusobject(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + alljoyn_busobject_destroy(BusObject); + BusObject = nullptr; + } + if (nullptr != SessionListener) + { + alljoyn_sessionlistener_destroy(SessionListener); + SessionListener = nullptr; + } +} + +bool OnboardingProducer::OnAcceptSessionJoiner(_In_ alljoyn_sessionport sessionPort, _In_ PCSTR joiner, _In_ const alljoyn_sessionopts opts) +{ + UNREFERENCED_PARAMETER(sessionPort); UNREFERENCED_PARAMETER(joiner); UNREFERENCED_PARAMETER(opts); + + return true; +} + +void OnboardingProducer::OnSessionJoined(_In_ alljoyn_sessionport sessionPort, _In_ alljoyn_sessionid id, _In_ PCSTR joiner) +{ + UNREFERENCED_PARAMETER(joiner); + + // We initialize the Signals object after the session has been joined, because it needs + // the session id. + m_signals->Initialize(BusObject, id); + m_sessionPort = sessionPort; + m_sessionId = id; + + alljoyn_sessionlistener_callbacks callbacks = + { + AllJoynHelpers::SessionLostHandler, + AllJoynHelpers::SessionMemberAddedHandler, + AllJoynHelpers::SessionMemberRemovedHandler + }; + + SessionListener = alljoyn_sessionlistener_create(&callbacks, m_weak); + alljoyn_busattachment_setsessionlistener(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), id, SessionListener); +} + +void OnboardingProducer::OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) +{ + if (sessionId == m_sessionId) + { + AllJoynSessionLostEventArgs^ args = ref new AllJoynSessionLostEventArgs(static_cast(reason)); + AllJoynHelpers::DispatchEvent([=]() { + SessionLost(this, args); + }); + } +} + +void OnboardingProducer::OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberAddedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + AllJoynHelpers::DispatchEvent([=]() { + SessionMemberAdded(this, args); + }); + } +} + +void OnboardingProducer::OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +{ + if (sessionId == m_sessionId) + { + auto args = ref new AllJoynSessionMemberRemovedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); + AllJoynHelpers::DispatchEvent([=]() { + SessionMemberRemoved(this, args); + }); + } +} + +void OnboardingProducer::BusAttachmentStateChanged(_In_ AllJoynBusAttachment^ sender, _In_ AllJoynBusAttachmentStateChangedEventArgs^ args) +{ + if (args->State == AllJoynBusAttachmentState::Connected) + { + QStatus result = AllJoynHelpers::CreateProducerSession(m_busAttachment, m_weak); + if (ER_OK != result) + { + StopInternal(result); + return; + } + } + else if (args->State == AllJoynBusAttachmentState::Disconnected) + { + StopInternal(ER_BUS_STOPPING); + } +} + +void OnboardingProducer::CallConfigureWiFiHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message) +{ + auto source = SourceObjects.find(busObject); + if (source == SourceObjects.end()) + { + return; + } + + OnboardingProducer^ producer = source->second->Resolve(); + if (producer->Service != nullptr) + { + AllJoynMessageInfo^ callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + + Platform::String^ inputArg0; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "s", &inputArg0); + Platform::String^ inputArg1; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 1), "s", &inputArg1); + int16 inputArg2; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 2), "n", &inputArg2); + + create_task(producer->Service->ConfigureWiFiAsync(callInfo, inputArg0, inputArg1, inputArg2)).then([busObject, message](OnboardingConfigureWiFiResult^ result) + { + int32 status; + + if (nullptr == result) + { + alljoyn_busobject_methodreply_status(busObject, message, ER_BUS_NO_LISTENER); + return; + } + + status = result->Status; + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + return; + } + + size_t argCount = 1; + alljoyn_msgarg outputs = alljoyn_msgarg_array_create(argCount); + + status = TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(outputs, 0), "n", result->Status2); + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + alljoyn_msgarg_destroy(outputs); + return; + } + + alljoyn_busobject_methodreply_args(busObject, message, outputs, argCount); + alljoyn_msgarg_destroy(outputs); + }).wait(); + } +} + +void OnboardingProducer::CallConnectHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message) +{ + auto source = SourceObjects.find(busObject); + if (source == SourceObjects.end()) + { + return; + } + + OnboardingProducer^ producer = source->second->Resolve(); + if (producer->Service != nullptr) + { + AllJoynMessageInfo^ callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + + + create_task(producer->Service->ConnectAsync(callInfo)).then([busObject, message](OnboardingConnectResult^ result) + { + int32 status; + + if (nullptr == result) + { + alljoyn_busobject_methodreply_status(busObject, message, ER_BUS_NO_LISTENER); + return; + } + + status = result->Status; + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + return; + } + + size_t argCount = 0; + alljoyn_msgarg outputs = alljoyn_msgarg_array_create(argCount); + + alljoyn_busobject_methodreply_args(busObject, message, outputs, argCount); + alljoyn_msgarg_destroy(outputs); + }).wait(); + } +} + +void OnboardingProducer::CallOffboardHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message) +{ + auto source = SourceObjects.find(busObject); + if (source == SourceObjects.end()) + { + return; + } + + OnboardingProducer^ producer = source->second->Resolve(); + if (producer->Service != nullptr) + { + AllJoynMessageInfo^ callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + + + create_task(producer->Service->OffboardAsync(callInfo)).then([busObject, message](OnboardingOffboardResult^ result) + { + int32 status; + + if (nullptr == result) + { + alljoyn_busobject_methodreply_status(busObject, message, ER_BUS_NO_LISTENER); + return; + } + + status = result->Status; + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + return; + } + + size_t argCount = 0; + alljoyn_msgarg outputs = alljoyn_msgarg_array_create(argCount); + + alljoyn_busobject_methodreply_args(busObject, message, outputs, argCount); + alljoyn_msgarg_destroy(outputs); + }).wait(); + } +} + +void OnboardingProducer::CallGetScanInfoHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message) +{ + auto source = SourceObjects.find(busObject); + if (source == SourceObjects.end()) + { + return; + } + + OnboardingProducer^ producer = source->second->Resolve(); + if (producer->Service != nullptr) + { + AllJoynMessageInfo^ callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + + + create_task(producer->Service->GetScanInfoAsync(callInfo)).then([busObject, message](OnboardingGetScanInfoResult^ result) + { + int32 status; + + if (nullptr == result) + { + alljoyn_busobject_methodreply_status(busObject, message, ER_BUS_NO_LISTENER); + return; + } + + status = result->Status; + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + return; + } + + size_t argCount = 2; + alljoyn_msgarg outputs = alljoyn_msgarg_array_create(argCount); + + status = TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(outputs, 0), "q", result->Age); + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + alljoyn_msgarg_destroy(outputs); + return; + } + + status = TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(outputs, 1), "a(sn)", result->ScanList); + if (AllJoynStatus::Ok != status) + { + alljoyn_busobject_methodreply_status(busObject, message, static_cast(status)); + alljoyn_msgarg_destroy(outputs); + return; + } + + alljoyn_busobject_methodreply_args(busObject, message, outputs, argCount); + alljoyn_msgarg_destroy(outputs); + }).wait(); + } +} + +void OnboardingProducer::CallConnectionResultSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message) +{ + auto source = SourceInterfaces.find(member->iface); + if (source == SourceInterfaces.end()) + { + return; + } + + auto producer = source->second->Resolve(); + if (producer->Signals != nullptr) + { + auto callInfo = ref new AllJoynMessageInfo(AllJoynHelpers::MultibyteToPlatformString(alljoyn_message_getsender(message))); + auto eventArgs = ref new OnboardingConnectionResultReceivedEventArgs(); + eventArgs->MessageInfo = callInfo; + + Onboarding^ argument0; + TypeConversionHelpers::GetAllJoynMessageArg(alljoyn_message_getarg(message, 0), "(ns)", &argument0); + eventArgs->Arg = argument0; + + producer->Signals->CallConnectionResultReceived(producer->Signals, eventArgs); + } +} + +QStatus OnboardingProducer::AddMethodHandler(_In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_methodhandler_ptr handler) +{ + alljoyn_interfacedescription_member member; + if (!alljoyn_interfacedescription_getmember(interfaceDescription, methodName, &member)) + { + return ER_BUS_INTERFACE_NO_SUCH_MEMBER; + } + + return alljoyn_busobject_addmethodhandler( + m_busObject, + member, + handler, + m_weak); +} + +QStatus OnboardingProducer::AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler) +{ + alljoyn_interfacedescription_member member; + if (!alljoyn_interfacedescription_getmember(interfaceDescription, methodName, &member)) + { + return ER_BUS_INTERFACE_NO_SUCH_MEMBER; + } + + return alljoyn_busattachment_registersignalhandler(busAttachment, handler, member, NULL); +} + +QStatus OnboardingProducer::OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg value) +{ + UNREFERENCED_PARAMETER(interfaceName); + + if (0 == strcmp(propertyName, "Version")) + { + auto task = create_task(Service->GetVersionAsync(nullptr)); + auto result = task.get(); + + if (AllJoynStatus::Ok != result->Status) + { + return static_cast(result->Status); + } + + return static_cast(TypeConversionHelpers::SetAllJoynMessageArg(value, "q", result->Version)); + } + if (0 == strcmp(propertyName, "State")) + { + auto task = create_task(Service->GetStateAsync(nullptr)); + auto result = task.get(); + + if (AllJoynStatus::Ok != result->Status) + { + return static_cast(result->Status); + } + + return static_cast(TypeConversionHelpers::SetAllJoynMessageArg(value, "n", result->State)); + } + if (0 == strcmp(propertyName, "LastError")) + { + auto task = create_task(Service->GetLastErrorAsync(nullptr)); + auto result = task.get(); + + if (AllJoynStatus::Ok != result->Status) + { + return static_cast(result->Status); + } + + return static_cast(TypeConversionHelpers::SetAllJoynMessageArg(value, "(ns)", result->LastError)); + } + + return ER_BUS_NO_SUCH_PROPERTY; +} + +QStatus OnboardingProducer::OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg value) +{ + UNREFERENCED_PARAMETER(interfaceName); + + return ER_BUS_NO_SUCH_PROPERTY; +} + +void OnboardingProducer::Start() +{ + if (nullptr == m_busAttachment) + { + StopInternal(ER_FAIL); + return; + } + + QStatus result = AllJoynHelpers::CreateInterfaces(m_busAttachment, c_OnboardingIntrospectionXml); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AllJoynHelpers::CreateBusObject(m_weak); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + alljoyn_interfacedescription interfaceDescription = alljoyn_busattachment_getinterface(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), "org.alljoyn.Onboarding"); + if (interfaceDescription == nullptr) + { + StopInternal(ER_FAIL); + return; + } + alljoyn_busobject_addinterface_announced(BusObject, interfaceDescription); + + result = AddMethodHandler( + interfaceDescription, + "ConfigureWiFi", + [](alljoyn_busobject busObject, const alljoyn_interfacedescription_member* member, alljoyn_message message) { UNREFERENCED_PARAMETER(member); CallConfigureWiFiHandler(busObject, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AddMethodHandler( + interfaceDescription, + "Connect", + [](alljoyn_busobject busObject, const alljoyn_interfacedescription_member* member, alljoyn_message message) { UNREFERENCED_PARAMETER(member); CallConnectHandler(busObject, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AddMethodHandler( + interfaceDescription, + "Offboard", + [](alljoyn_busobject busObject, const alljoyn_interfacedescription_member* member, alljoyn_message message) { UNREFERENCED_PARAMETER(member); CallOffboardHandler(busObject, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AddMethodHandler( + interfaceDescription, + "GetScanInfo", + [](alljoyn_busobject busObject, const alljoyn_interfacedescription_member* member, alljoyn_message message) { UNREFERENCED_PARAMETER(member); CallGetScanInfoHandler(busObject, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + result = AddSignalHandler( + AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), + interfaceDescription, + "ConnectionResult", + [](const alljoyn_interfacedescription_member* member, PCSTR srcPath, alljoyn_message message) { UNREFERENCED_PARAMETER(srcPath); CallConnectionResultSignalHandler(member, message); }); + if (result != ER_OK) + { + StopInternal(result); + return; + } + + SourceObjects[m_busObject] = m_weak; + SourceInterfaces[interfaceDescription] = m_weak; + + unsigned int noneMechanismIndex = 0; + bool authenticationMechanismsContainsNone = m_busAttachment->AuthenticationMechanisms->IndexOf(AllJoynAuthenticationMechanism::None, &noneMechanismIndex); + QCC_BOOL interfaceIsSecure = alljoyn_interfacedescription_issecure(interfaceDescription); + + // If the current set of AuthenticationMechanisms supports authentication, + // determine whether a secure BusObject is required. + if (AllJoynHelpers::CanSecure(m_busAttachment->AuthenticationMechanisms)) + { + // Register the BusObject as "secure" if the org.alljoyn.Bus.Secure XML annotation + // is specified, or if None is not present in AuthenticationMechanisms. + if (!authenticationMechanismsContainsNone || interfaceIsSecure) + { + result = alljoyn_busattachment_registerbusobject_secure(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + } + else + { + result = alljoyn_busattachment_registerbusobject(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + } + } + else + { + // If the current set of AuthenticationMechanisms does not support authentication + // but the interface requires security, report an error. + if (interfaceIsSecure) + { + result = ER_BUS_NO_AUTHENTICATION_MECHANISM; + } + else + { + result = alljoyn_busattachment_registerbusobject(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), BusObject); + } + } + + if (result != ER_OK) + { + StopInternal(result); + return; + } + + m_busAttachmentStateChangedToken = m_busAttachment->StateChanged += ref new TypedEventHandler(this, &OnboardingProducer::BusAttachmentStateChanged); + m_busAttachment->Connect(); +} + +void OnboardingProducer::Stop() +{ + StopInternal(AllJoynStatus::Ok); +} + +void OnboardingProducer::StopInternal(int32 status) +{ + UnregisterFromBus(); + Stopped(this, ref new AllJoynProducerStoppedEventArgs(status)); +} + +int32 OnboardingProducer::RemoveMemberFromSession(_In_ String^ uniqueName) +{ + return alljoyn_busattachment_removesessionmember( + AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), + m_sessionId, + AllJoynHelpers::PlatformToMultibyteString(uniqueName).data()); +} + +PCSTR org::alljoyn::Onboarding::c_OnboardingIntrospectionXml = "" +" A secure onboarding interface" +" " +" " +" Interface version number" +" " +" " +" " +" The configuration state" +" " +" " +" " +" The last error code and error message" +" " +" " +" " +" Sends the personal AP information to the onboardee" +" " +" " +" " +" " +" " +" " +" Tells the onboardee to connect to the personal AP" +" " +" " +" " +" Tells the onboardee to disconnect from the personal AP" +" " +" " +" " +" Scans all the Wi-Fi access points in the onboardee's proximity" +" " +" " +" " +" " +" This signal is emitted when the connection attempt against the personal AP is completed" +" " +" " +"" +; diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h new file mode 100644 index 0000000000..2ed07f74ce --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h @@ -0,0 +1,174 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +extern PCSTR c_OnboardingIntrospectionXml; + +ref class OnboardingProducer; + +public interface class IOnboardingProducer +{ + event Windows::Foundation::TypedEventHandler^ Stopped; + event Windows::Foundation::TypedEventHandler^ SessionLost; + event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; +}; + +public ref class OnboardingProducer sealed : [Windows::Foundation::Metadata::Default] IOnboardingProducer +{ +public: + OnboardingProducer(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + virtual ~OnboardingProducer(); + + // The implementation of IOnboardingService that will handle method calls and property requests. + property IOnboardingService^ Service + { + IOnboardingService^ get() { return m_serviceInterface; } + void set(IOnboardingService^ value) { m_serviceInterface = value; } + } + + // Used to send signals or register functions to handle received signals. + property OnboardingSignals^ Signals + { + OnboardingSignals^ get() { return m_signals; } + } + + // This event will fire whenever this producer is stopped. + virtual event Windows::Foundation::TypedEventHandler^ Stopped; + + // This event will fire whenever the producer loses the session that it created. + virtual event Windows::Foundation::TypedEventHandler^ SessionLost; + + // This event will fire whenever a member joins the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; + + // This event will fire whenever a member leaves the session. + virtual event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; + + // Start advertising the service. + void Start(); + + // Stop advertising the service. + void Stop(); + + // Remove a member that has joined this session. + int32 RemoveMemberFromSession(_In_ Platform::String^ uniqueName); + +internal: + bool OnAcceptSessionJoiner(_In_ alljoyn_sessionport sessionPort, _In_ PCSTR joiner, _In_ const alljoyn_sessionopts opts); + void OnSessionJoined(_In_ alljoyn_sessionport sessionPort, _In_ alljoyn_sessionid id, _In_ PCSTR joiner); + QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val); + QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val); + void OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason); + void OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + void OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); + + property Platform::String^ ServiceObjectPath + { + Platform::String^ get() { return m_ServiceObjectPath; } + void set(Platform::String^ value) { m_ServiceObjectPath = value; } + } + + property alljoyn_busobject BusObject + { + alljoyn_busobject get() { return m_busObject; } + void set(alljoyn_busobject value) { m_busObject = value; } + } + + property alljoyn_sessionportlistener SessionPortListener + { + alljoyn_sessionportlistener get() { return m_sessionPortListener; } + void set(alljoyn_sessionportlistener value) { m_sessionPortListener = value; } + } + + property alljoyn_sessionlistener SessionListener + { + alljoyn_sessionlistener get() { return m_sessionListener; } + void set(alljoyn_sessionlistener value) { m_sessionListener = value; } + } + + property alljoyn_sessionport SessionPort + { + alljoyn_sessionport get() { return m_sessionPort; } + internal: + void set(alljoyn_sessionport value) { m_sessionPort = value; } + } + + property alljoyn_sessionid SessionId + { + alljoyn_sessionid get() { return m_sessionId; } + } + + // Stop advertising the service and pass status to anyone listening for the Stopped event. + void StopInternal(int32 status); + + void BusAttachmentStateChanged(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ sender, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachmentStateChangedEventArgs^ args); + +private: + static void CallConfigureWiFiHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + static void CallConnectHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + static void CallOffboardHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + static void CallGetScanInfoHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + static void CallConnectionResultSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); + + // Register a callback function to handle methods. + QStatus AddMethodHandler(_In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_methodhandler_ptr handler); + // Register a callback function to handle incoming signals. + QStatus AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler); + + void UnregisterFromBus(); + + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; + OnboardingSignals^ m_signals; + IOnboardingService^ m_serviceInterface; + Platform::String^ m_ServiceObjectPath; + + alljoyn_busobject m_busObject; + alljoyn_sessionportlistener m_sessionPortListener; + alljoyn_sessionlistener m_sessionListener; + alljoyn_sessionport m_sessionPort; + alljoyn_sessionid m_sessionId; + + // Used to pass a pointer to this class to callbacks + Platform::WeakReference* m_weak; + + // These maps are required because we need a way to pass the producer to the method + // and signal handlers, but the current AllJoyn C API does not allow passing a context to these + // callbacks. + static std::map SourceObjects; + static std::map SourceInterfaces; +}; + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp new file mode 100644 index 0000000000..326ef44a3f --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp @@ -0,0 +1,111 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Devices::AllJoyn; +using namespace org::alljoyn::Onboarding; + +// Note: Unlike an Interface implementation, which provides a single handler for each member, the event +// model allows for 0 or more listeners to be registered. The EventAdapter implementation deals with this +// difference by implementing a last-writer-wins policy. The lack of any return value (i.e., 0 listeners) +// is handled by returning a null result. + +// Methods +IAsyncOperation^ OnboardingServiceEventAdapter::ConfigureWiFiAsync(_In_ AllJoynMessageInfo^ info, _In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType) +{ + auto args = ref new OnboardingConfigureWiFiCalledEventArgs(info, interfaceMemberSSID, interfaceMemberPassphrase, interfaceMemberAuthType); + AllJoynHelpers::DispatchEvent([=]() { + ConfigureWiFiCalled(this, args); + }); + return OnboardingConfigureWiFiCalledEventArgs::GetResultAsync(args); +} + +IAsyncOperation^ OnboardingServiceEventAdapter::ConnectAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new OnboardingConnectCalledEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + ConnectCalled(this, args); + }); + return OnboardingConnectCalledEventArgs::GetResultAsync(args); +} + +IAsyncOperation^ OnboardingServiceEventAdapter::OffboardAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new OnboardingOffboardCalledEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + OffboardCalled(this, args); + }); + return OnboardingOffboardCalledEventArgs::GetResultAsync(args); +} + +IAsyncOperation^ OnboardingServiceEventAdapter::GetScanInfoAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new OnboardingGetScanInfoCalledEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + GetScanInfoCalled(this, args); + }); + return OnboardingGetScanInfoCalledEventArgs::GetResultAsync(args); +} + +// Property Reads +IAsyncOperation^ OnboardingServiceEventAdapter::GetVersionAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new OnboardingGetVersionRequestedEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + GetVersionRequested(this, args); + }); + return OnboardingGetVersionRequestedEventArgs::GetResultAsync(args); +} + +IAsyncOperation^ OnboardingServiceEventAdapter::GetStateAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new OnboardingGetStateRequestedEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + GetStateRequested(this, args); + }); + return OnboardingGetStateRequestedEventArgs::GetResultAsync(args); +} + +IAsyncOperation^ OnboardingServiceEventAdapter::GetLastErrorAsync(_In_ AllJoynMessageInfo^ info) +{ + auto args = ref new OnboardingGetLastErrorRequestedEventArgs(info); + AllJoynHelpers::DispatchEvent([=]() { + GetLastErrorRequested(this, args); + }); + return OnboardingGetLastErrorRequestedEventArgs::GetResultAsync(args); +} + +// Property Writes diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h new file mode 100644 index 0000000000..2e69913a95 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h @@ -0,0 +1,67 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +// This class, and the associated EventArgs classes, exist for the benefit of JavaScript developers who +// do not have the ability to implement IOnboardingService. Instead, OnboardingServiceEventAdapter +// provides the Interface implementation and exposes a set of compatible events to the developer. +public ref class OnboardingServiceEventAdapter sealed : [Windows::Foundation::Metadata::Default] IOnboardingService +{ +public: + // Method Invocation Events + event Windows::Foundation::TypedEventHandler^ ConfigureWiFiCalled; + event Windows::Foundation::TypedEventHandler^ ConnectCalled; + event Windows::Foundation::TypedEventHandler^ OffboardCalled; + event Windows::Foundation::TypedEventHandler^ GetScanInfoCalled; + + // Property Read Events + event Windows::Foundation::TypedEventHandler^ GetVersionRequested; + event Windows::Foundation::TypedEventHandler^ GetStateRequested; + event Windows::Foundation::TypedEventHandler^ GetLastErrorRequested; + + // Property Write Events + + // IOnboardingService Implementation + virtual Windows::Foundation::IAsyncOperation^ ConfigureWiFiAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, _In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType); + virtual Windows::Foundation::IAsyncOperation^ ConnectAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + virtual Windows::Foundation::IAsyncOperation^ OffboardAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + virtual Windows::Foundation::IAsyncOperation^ GetScanInfoAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + virtual Windows::Foundation::IAsyncOperation^ GetVersionAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + virtual Windows::Foundation::IAsyncOperation^ GetStateAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + virtual Windows::Foundation::IAsyncOperation^ GetLastErrorAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + +}; + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp new file mode 100644 index 0000000000..38dabbf887 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp @@ -0,0 +1,577 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Devices::AllJoyn; +using namespace org::alljoyn::Onboarding; +namespace org { namespace alljoyn { namespace Onboarding { + +// Methods +OnboardingConfigureWiFiCalledEventArgs::OnboardingConfigureWiFiCalledEventArgs( + _In_ AllJoynMessageInfo^ info, + _In_ Platform::String^ interfaceMemberSSID, + _In_ Platform::String^ interfaceMemberPassphrase, + _In_ int16 interfaceMemberAuthType) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info), + m_interfaceMemberSSID(interfaceMemberSSID), + m_interfaceMemberPassphrase(interfaceMemberPassphrase), + m_interfaceMemberAuthType(interfaceMemberAuthType) +{ + m_result = OnboardingConfigureWiFiResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingConfigureWiFiCalledEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingConfigureWiFiCalledEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingConfigureWiFiCalledEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingConfigureWiFiCalledEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingConfigureWiFiCalledEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for ConfigureWiFiCalled."); + } + else + { + m_tce.set(m_result); + } +} + +OnboardingConnectCalledEventArgs::OnboardingConnectCalledEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = OnboardingConnectResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingConnectCalledEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingConnectCalledEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingConnectCalledEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingConnectCalledEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingConnectCalledEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for ConnectCalled."); + } + else + { + m_tce.set(m_result); + } +} + +OnboardingOffboardCalledEventArgs::OnboardingOffboardCalledEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = OnboardingOffboardResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingOffboardCalledEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingOffboardCalledEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingOffboardCalledEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingOffboardCalledEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingOffboardCalledEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for OffboardCalled."); + } + else + { + m_tce.set(m_result); + } +} + +OnboardingGetScanInfoCalledEventArgs::OnboardingGetScanInfoCalledEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = OnboardingGetScanInfoResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingGetScanInfoCalledEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingGetScanInfoCalledEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingGetScanInfoCalledEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetScanInfoCalledEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetScanInfoCalledEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for GetScanInfoCalled."); + } + else + { + m_tce.set(m_result); + } +} + +// Readable Properties +OnboardingGetVersionRequestedEventArgs::OnboardingGetVersionRequestedEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = OnboardingGetVersionResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingGetVersionRequestedEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingGetVersionRequestedEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingGetVersionRequestedEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetVersionRequestedEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetVersionRequestedEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for GetVersionRequested."); + } + else + { + m_tce.set(m_result); + } +} + +OnboardingGetStateRequestedEventArgs::OnboardingGetStateRequestedEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = OnboardingGetStateResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingGetStateRequestedEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingGetStateRequestedEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingGetStateRequestedEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetStateRequestedEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetStateRequestedEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for GetStateRequested."); + } + else + { + m_tce.set(m_result); + } +} + +OnboardingGetLastErrorRequestedEventArgs::OnboardingGetLastErrorRequestedEventArgs( + _In_ AllJoynMessageInfo^ info) + : m_raised(false), + m_completionsRequired(0), + m_messageInfo(info) +{ + m_result = OnboardingGetLastErrorResult::CreateFailureResult(ER_NOT_IMPLEMENTED); +} + +Deferral^ OnboardingGetLastErrorRequestedEventArgs::GetDeferral() +{ + std::lock_guard lockGuard(m_lock); + if (m_raised) + { + // Cannot ask for a deferral after the event handler has returned. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + + m_completionsRequired++; + auto handler = ref new DeferralCompletedHandler(this, &OnboardingGetLastErrorRequestedEventArgs::Complete); + return ref new Deferral(handler); +} + +void OnboardingGetLastErrorRequestedEventArgs::InvokeAllFinished() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + m_raised = true; + invokeNeeded = (m_completionsRequired == 0); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetLastErrorRequestedEventArgs::Complete() +{ + bool invokeNeeded; + + // We need to hold a lock while modifying private state, but release it before invoking a completion handler. + { + std::lock_guard lockGuard(m_lock); + if (m_completionsRequired == 0) + { + // This should never happen since Complete() should only be called by Windows.Foundation.Deferral + // which will only invoke our completion handler once. + throw Exception::CreateException(E_ILLEGAL_METHOD_CALL); + } + m_completionsRequired--; + invokeNeeded = (m_raised && (m_completionsRequired == 0)); + } + + if (invokeNeeded) + { + InvokeCompleteHandler(); + } +} + +void OnboardingGetLastErrorRequestedEventArgs::InvokeCompleteHandler() +{ + if (m_result->Status == ER_NOT_IMPLEMENTED) + { + throw Exception::CreateException(E_NOTIMPL, "No handlers are registered for GetLastErrorRequested."); + } + else + { + m_tce.set(m_result); + } +} + +// Writable Properties +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h new file mode 100644 index 0000000000..3610c12a76 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h @@ -0,0 +1,344 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +// Methods +public ref class OnboardingConfigureWiFiCalledEventArgs sealed +{ +public: + OnboardingConfigureWiFiCalledEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info, _In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingConfigureWiFiResult^ Result + { + OnboardingConfigureWiFiResult^ get() { return m_result; } + void set(_In_ OnboardingConfigureWiFiResult^ value) { m_result = value; } + } + + property Platform::String^ SSID + { + Platform::String^ get() { return m_interfaceMemberSSID; } + } + + property Platform::String^ Passphrase + { + Platform::String^ get() { return m_interfaceMemberPassphrase; } + } + + property int16 AuthType + { + int16 get() { return m_interfaceMemberAuthType; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingConfigureWiFiCalledEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingConfigureWiFiResult^ m_result; + Platform::String^ m_interfaceMemberSSID; + Platform::String^ m_interfaceMemberPassphrase; + int16 m_interfaceMemberAuthType; +}; + +public ref class OnboardingConnectCalledEventArgs sealed +{ +public: + OnboardingConnectCalledEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingConnectResult^ Result + { + OnboardingConnectResult^ get() { return m_result; } + void set(_In_ OnboardingConnectResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingConnectCalledEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingConnectResult^ m_result; +}; + +public ref class OnboardingOffboardCalledEventArgs sealed +{ +public: + OnboardingOffboardCalledEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingOffboardResult^ Result + { + OnboardingOffboardResult^ get() { return m_result; } + void set(_In_ OnboardingOffboardResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingOffboardCalledEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingOffboardResult^ m_result; +}; + +public ref class OnboardingGetScanInfoCalledEventArgs sealed +{ +public: + OnboardingGetScanInfoCalledEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingGetScanInfoResult^ Result + { + OnboardingGetScanInfoResult^ get() { return m_result; } + void set(_In_ OnboardingGetScanInfoResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingGetScanInfoCalledEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingGetScanInfoResult^ m_result; +}; + +// Readable Properties +public ref class OnboardingGetVersionRequestedEventArgs sealed +{ +public: + OnboardingGetVersionRequestedEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingGetVersionResult^ Result + { + OnboardingGetVersionResult^ get() { return m_result; } + void set(_In_ OnboardingGetVersionResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingGetVersionRequestedEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingGetVersionResult^ m_result; +}; + +public ref class OnboardingGetStateRequestedEventArgs sealed +{ +public: + OnboardingGetStateRequestedEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingGetStateResult^ Result + { + OnboardingGetStateResult^ get() { return m_result; } + void set(_In_ OnboardingGetStateResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingGetStateRequestedEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingGetStateResult^ m_result; +}; + +public ref class OnboardingGetLastErrorRequestedEventArgs sealed +{ +public: + OnboardingGetLastErrorRequestedEventArgs(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + + property Windows::Devices::AllJoyn::AllJoynMessageInfo^ MessageInfo + { + Windows::Devices::AllJoyn::AllJoynMessageInfo^ get() { return m_messageInfo; } + } + + property OnboardingGetLastErrorResult^ Result + { + OnboardingGetLastErrorResult^ get() { return m_result; } + void set(_In_ OnboardingGetLastErrorResult^ value) { m_result = value; } + } + + Windows::Foundation::Deferral^ GetDeferral(); + + static Windows::Foundation::IAsyncOperation^ GetResultAsync(OnboardingGetLastErrorRequestedEventArgs^ args) + { + args->InvokeAllFinished(); + auto t = concurrency::create_task(args->m_tce); + return concurrency::create_async([t]() -> concurrency::task + { + return t; + }); + } + +private: + void Complete(); + void InvokeAllFinished(); + void InvokeCompleteHandler(); + + bool m_raised; + int m_completionsRequired; + concurrency::task_completion_event m_tce; + std::mutex m_lock; + Windows::Devices::AllJoyn::AllJoynMessageInfo^ m_messageInfo; + OnboardingGetLastErrorResult^ m_result; +}; + +// Writable Properties +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp new file mode 100644 index 0000000000..b5d59b5cdd --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp @@ -0,0 +1,80 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Devices::AllJoyn; +using namespace Windows::Foundation; +using namespace org::alljoyn::Onboarding; + +void OnboardingSignals::Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId) +{ + m_busObject = busObject; + m_sessionId = sessionId; + + auto interfaceDefinition = alljoyn_busattachment_getinterface(alljoyn_busobject_getbusattachment(busObject), "org.alljoyn.Onboarding"); + alljoyn_interfacedescription_getmember(interfaceDefinition, "ConnectionResult", &m_memberConnectionResult); +} + +void OnboardingSignals::ConnectionResult(_In_ Onboarding^ interfaceMemberArg) +{ + if (nullptr == m_busObject) + { + return; + } + + size_t argCount = 1; + alljoyn_msgarg arguments = alljoyn_msgarg_array_create(argCount); + TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(arguments, 0), "(ns)", interfaceMemberArg); + + alljoyn_busobject_signal( + m_busObject, + NULL, // Generated code only supports broadcast signals. + m_sessionId, + m_memberConnectionResult, + arguments, + argCount, + 0, // A signal with a TTL of 0 will be sent to every member of the session, regardless of how long it takes to deliver the message + ALLJOYN_MESSAGE_FLAG_GLOBAL_BROADCAST, // Broadcast to everyone in the session. + NULL); // The generated code does not need the generated signal message + + alljoyn_msgarg_destroy(arguments); +} + +void OnboardingSignals::CallConnectionResultReceived(_In_ OnboardingSignals^ sender, _In_ OnboardingConnectionResultReceivedEventArgs^ args) +{ + AllJoynHelpers::DispatchEvent([=]() { + ConnectionResultReceived(sender, args); + }); +} + diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.h new file mode 100644 index 0000000000..8f34db21b2 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +ref class OnboardingSignals; + +public interface class IOnboardingSignals +{ + event Windows::Foundation::TypedEventHandler^ ConnectionResultReceived; +}; + +public ref class OnboardingSignals sealed : [Windows::Foundation::Metadata::Default] IOnboardingSignals +{ +public: + // Calling this method will send the ConnectionResult signal to every member of the session. + void ConnectionResult(_In_ Onboarding^ interfaceMemberArg); + + // This event fires whenever the ConnectionResult signal is sent by another member of the session. + virtual event Windows::Foundation::TypedEventHandler^ ConnectionResultReceived; + +internal: + void Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId); + void CallConnectionResultReceived(_In_ OnboardingSignals^ sender, _In_ OnboardingConnectionResultReceivedEventArgs^ args); + +private: + alljoyn_busobject m_busObject; + alljoyn_sessionid m_sessionId; + + alljoyn_interfacedescription_member m_memberConnectionResult; +}; + +} } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingStructures.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingStructures.h new file mode 100644 index 0000000000..1a7511f4a3 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingStructures.h @@ -0,0 +1,290 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +public ref class OnboardingScanListItem sealed +{ +public: + property Platform::String^ Value1 + { + Platform::String^ get() { return m_value1; } + void set(Platform::String^ value) { m_value1 = value; } + } + + property int16 Value2 + { + int16 get() { return m_value2; } + void set(int16 value) { m_value2 = value; } + } + +private: + Platform::String^ m_value1; + int16 m_value2; +}; + +public ref class Onboarding sealed +{ +public: + property int16 Value1 + { + int16 get() { return m_value1; } + void set(int16 value) { m_value1 = value; } + } + + property Platform::String^ Value2 + { + Platform::String^ get() { return m_value2; } + void set(Platform::String^ value) { m_value2 = value; } + } + +private: + int16 m_value1; + Platform::String^ m_value2; +}; + +public ref class OnboardingLastError sealed +{ +public: + property int16 Value1 + { + int16 get() { return m_value1; } + void set(int16 value) { m_value1 = value; } + } + + property Platform::String^ Value2 + { + Platform::String^ get() { return m_value2; } + void set(Platform::String^ value) { m_value2 = value; } + } + +private: + int16 m_value1; + Platform::String^ m_value2; +}; + +public ref class AllJoynMessageArgStructure sealed : Windows::Foundation::Collections::IVector +{ +public: + AllJoynMessageArgStructure() + { + m_vector = ref new Platform::Collections::Vector(); + } + + virtual Windows::Foundation::Collections::IIterator^ First() + { + return m_vector->First(); + } + + virtual Platform::Object^ GetAt(unsigned int index) + { + return m_vector->GetAt(index); + } + + virtual property unsigned int Size { + virtual unsigned int get() + { + return m_vector->Size; + } + } + + virtual bool IndexOf(Platform::Object^ value, unsigned int * index) + { + return m_vector->IndexOf(value, index); + } + + virtual unsigned int GetMany(unsigned int startIndex, Platform::WriteOnlyArray^ items) + { + return m_vector->GetMany(startIndex, items); + } + + virtual Windows::Foundation::Collections::IVectorView^ GetView() + { + return m_vector->GetView(); + } + + virtual void SetAt(unsigned int index, Platform::Object^ item) + { + return m_vector->SetAt(index, item); + } + + virtual void InsertAt(unsigned int index, Platform::Object^ item) + { + return m_vector->InsertAt(index, item); + } + + virtual void Append(Platform::Object^ item) + { + return m_vector->Append(item); + } + + virtual void RemoveAt(unsigned int index) + { + return m_vector->RemoveAt(index); + } + + virtual void RemoveAtEnd() + { + return m_vector->RemoveAtEnd(); + } + + virtual void Clear() + { + return m_vector->Clear(); + } + + virtual void ReplaceAll(const Platform::Array^ arr) + { + return m_vector->ReplaceAll(arr); + } + +private: + Platform::Collections::Vector^ m_vector; +}; +} } } + +partial ref class TypeConversionHelpers +{ +internal: + static _Check_return_ int32 GetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _Out_ org::alljoyn::Onboarding::OnboardingScanListItem^* value) + { + UNREFERENCED_PARAMETER(signature); + + (*value) = ref new org::alljoyn::Onboarding::OnboardingScanListItem(); + + alljoyn_msgarg argument1; + alljoyn_msgarg argument2; + RETURN_IF_QSTATUS_ERROR(alljoyn_msgarg_get(argument, "(**)", &argument1, &argument2)); + + Platform::String^ value1; + RETURN_IF_QSTATUS_ERROR(GetAllJoynMessageArg(argument1, "s", &value1)); + (*value)->Value1 = value1; + int16 value2; + RETURN_IF_QSTATUS_ERROR(GetAllJoynMessageArg(argument2, "n", &value2)); + (*value)->Value2 = value2; + + return ER_OK; + } + + static _Check_return_ int32 SetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _In_ org::alljoyn::Onboarding::OnboardingScanListItem^ value) + { + UNREFERENCED_PARAMETER(signature); + + auto argument1 = alljoyn_msgarg_create(); + RETURN_IF_QSTATUS_ERROR(SetAllJoynMessageArg(argument1, "s", value->Value1)); + auto argument2 = alljoyn_msgarg_create(); + RETURN_IF_QSTATUS_ERROR(SetAllJoynMessageArg(argument2, "n", value->Value2)); + + RETURN_IF_QSTATUS_ERROR(alljoyn_msgarg_set(argument, "(**)", argument1, argument2)); + alljoyn_msgarg_stabilize(argument); + alljoyn_msgarg_destroy(argument1); + alljoyn_msgarg_destroy(argument2); + + return ER_OK; + } + + static _Check_return_ int32 GetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _Out_ org::alljoyn::Onboarding::Onboarding^* value) + { + UNREFERENCED_PARAMETER(signature); + + (*value) = ref new org::alljoyn::Onboarding::Onboarding(); + + alljoyn_msgarg argument1; + alljoyn_msgarg argument2; + RETURN_IF_QSTATUS_ERROR(alljoyn_msgarg_get(argument, "(**)", &argument1, &argument2)); + + int16 value1; + RETURN_IF_QSTATUS_ERROR(GetAllJoynMessageArg(argument1, "n", &value1)); + (*value)->Value1 = value1; + Platform::String^ value2; + RETURN_IF_QSTATUS_ERROR(GetAllJoynMessageArg(argument2, "s", &value2)); + (*value)->Value2 = value2; + + return ER_OK; + } + + static _Check_return_ int32 SetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _In_ org::alljoyn::Onboarding::Onboarding^ value) + { + UNREFERENCED_PARAMETER(signature); + + auto argument1 = alljoyn_msgarg_create(); + RETURN_IF_QSTATUS_ERROR(SetAllJoynMessageArg(argument1, "n", value->Value1)); + auto argument2 = alljoyn_msgarg_create(); + RETURN_IF_QSTATUS_ERROR(SetAllJoynMessageArg(argument2, "s", value->Value2)); + + RETURN_IF_QSTATUS_ERROR(alljoyn_msgarg_set(argument, "(**)", argument1, argument2)); + alljoyn_msgarg_stabilize(argument); + alljoyn_msgarg_destroy(argument1); + alljoyn_msgarg_destroy(argument2); + + return ER_OK; + } + + static _Check_return_ int32 GetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _Out_ org::alljoyn::Onboarding::OnboardingLastError^* value) + { + UNREFERENCED_PARAMETER(signature); + + (*value) = ref new org::alljoyn::Onboarding::OnboardingLastError(); + + alljoyn_msgarg argument1; + alljoyn_msgarg argument2; + RETURN_IF_QSTATUS_ERROR(alljoyn_msgarg_get(argument, "(**)", &argument1, &argument2)); + + int16 value1; + RETURN_IF_QSTATUS_ERROR(GetAllJoynMessageArg(argument1, "n", &value1)); + (*value)->Value1 = value1; + Platform::String^ value2; + RETURN_IF_QSTATUS_ERROR(GetAllJoynMessageArg(argument2, "s", &value2)); + (*value)->Value2 = value2; + + return ER_OK; + } + + static _Check_return_ int32 SetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _In_ org::alljoyn::Onboarding::OnboardingLastError^ value) + { + UNREFERENCED_PARAMETER(signature); + + auto argument1 = alljoyn_msgarg_create(); + RETURN_IF_QSTATUS_ERROR(SetAllJoynMessageArg(argument1, "n", value->Value1)); + auto argument2 = alljoyn_msgarg_create(); + RETURN_IF_QSTATUS_ERROR(SetAllJoynMessageArg(argument2, "s", value->Value2)); + + RETURN_IF_QSTATUS_ERROR(alljoyn_msgarg_set(argument, "(**)", argument1, argument2)); + alljoyn_msgarg_stabilize(argument); + alljoyn_msgarg_destroy(argument1); + alljoyn_msgarg_destroy(argument2); + + return ER_OK; + } + +}; diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.cpp new file mode 100644 index 0000000000..13b2e5d251 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.cpp @@ -0,0 +1,153 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace concurrency; +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Devices::AllJoyn; +using namespace org::alljoyn::Onboarding; + +OnboardingWatcher::OnboardingWatcher(AllJoynBusAttachment^ busAttachment) : + m_aboutListener(nullptr) +{ + m_busAttachment = busAttachment; + m_weak = new WeakReference(this); + m_busAttachmentStateChangedToken.Value = 0; +} + +OnboardingWatcher::~OnboardingWatcher() +{ + UnregisterFromBus(); +} + +void OnboardingWatcher::UnregisterFromBus() +{ + if (nullptr != m_aboutListener) + { + PCSTR interfaces[] = { "org.alljoyn.Onboarding" }; + alljoyn_busattachment_cancelwhoimplements_interfaces( + AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), + interfaces, + _countof(interfaces)); + + alljoyn_busattachment_unregisteraboutlistener(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), m_aboutListener); + alljoyn_aboutlistener_destroy(m_aboutListener); + m_aboutListener = nullptr; + } + if ((nullptr != m_busAttachment) && (0 != m_busAttachmentStateChangedToken.Value)) + { + m_busAttachment->StateChanged -= m_busAttachmentStateChangedToken; + } +} + +void OnboardingWatcher::OnAnnounce( + _In_ PCSTR name, + _In_ uint16_t version, + _In_ alljoyn_sessionport port, + _In_ alljoyn_msgarg objectDescriptionArg, + _In_ const alljoyn_msgarg aboutDataArg) +{ + UNREFERENCED_PARAMETER(version); + UNREFERENCED_PARAMETER(aboutDataArg); + + alljoyn_aboutobjectdescription objectDescription = alljoyn_aboutobjectdescription_create_full(objectDescriptionArg); + + if (alljoyn_aboutobjectdescription_hasinterface(objectDescription, "org.alljoyn.Onboarding")) + { + AllJoynServiceInfo^ args = ref new AllJoynServiceInfo( + AllJoynHelpers::MultibyteToPlatformString(name), + AllJoynHelpers::GetObjectPath(objectDescription, "org.alljoyn.Onboarding"), + port); + Added(this, args); + } + alljoyn_aboutobjectdescription_destroy(objectDescription); +} + +void OnboardingWatcher::BusAttachmentStateChanged(_In_ AllJoynBusAttachment^ sender, _In_ AllJoynBusAttachmentStateChangedEventArgs^ args) +{ + if (args->State == AllJoynBusAttachmentState::Connected) + { + alljoyn_aboutlistener_callback callbacks = + { + AllJoynHelpers::AnnounceHandler + }; + m_aboutListener = alljoyn_aboutlistener_create(&callbacks, m_weak); + + alljoyn_busattachment_registeraboutlistener(AllJoynHelpers::GetInternalBusAttachment(sender), m_aboutListener); + PCSTR interfaces[] = { "org.alljoyn.Onboarding" }; + + auto status = alljoyn_busattachment_whoimplements_interfaces( + AllJoynHelpers::GetInternalBusAttachment(sender), + interfaces, + _countof(interfaces)); + if (ER_OK != status) + { + StopInternal(status); + } + } + else if (args->State == AllJoynBusAttachmentState::Disconnected) + { + StopInternal(ER_BUS_STOPPING); + } +} + +void OnboardingWatcher::Start() +{ + if (nullptr == m_busAttachment) + { + StopInternal(ER_FAIL); + return; + } + + int32 result = AllJoynHelpers::CreateInterfaces(m_busAttachment, c_OnboardingIntrospectionXml); + if (result != AllJoynStatus::Ok) + { + StopInternal(result); + return; + } + + m_busAttachmentStateChangedToken = m_busAttachment->StateChanged += ref new TypedEventHandler(this, &OnboardingWatcher::BusAttachmentStateChanged); + m_busAttachment->Connect(); +} + +void OnboardingWatcher::Stop() +{ + StopInternal(AllJoynStatus::Ok); +} + +void OnboardingWatcher::StopInternal(int32 status) +{ + UnregisterFromBus(); + Stopped(this, ref new AllJoynProducerStoppedEventArgs(status)); +} \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.h new file mode 100644 index 0000000000..7252e2180d --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.h @@ -0,0 +1,97 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +ref class OnboardingWatcher; + +public interface class IOnboardingWatcher +{ + event Windows::Foundation::TypedEventHandler^ Added; + event Windows::Foundation::TypedEventHandler^ Stopped; +}; + +public ref class OnboardingWatcher sealed : [Windows::Foundation::Metadata::Default] IOnboardingWatcher +{ +public: + OnboardingWatcher(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + virtual ~OnboardingWatcher(); + + // This event will fire whenever a producer for this service is found. + virtual event Windows::Foundation::TypedEventHandler^ Added; + + // This event will fire whenever the watcher is stopped. + virtual event Windows::Foundation::TypedEventHandler^ Stopped; + + // Start watching for producers advertising this service. + void Start(); + + // Stop watching for producers for this service. + void Stop(); + +internal: + void OnAnnounce( + _In_ PCSTR name, + _In_ uint16_t version, + _In_ alljoyn_sessionport port, + _In_ alljoyn_msgarg objectDescriptionArg, + _In_ const alljoyn_msgarg aboutDataArg); + + void OnPropertyChanged(_In_ PCSTR prop_name, _In_ alljoyn_msgarg prop_value) + { + UNREFERENCED_PARAMETER(prop_name); UNREFERENCED_PARAMETER(prop_value); + } + + property Windows::Devices::AllJoyn::AllJoynBusAttachment^ BusAttachment + { + Windows::Devices::AllJoyn::AllJoynBusAttachment^ get() { return m_busAttachment; } + } + + // Stop watching for producers advertising this service and pass status to anyone listening for the Stopped event. + void StopInternal(int32 status); + + void BusAttachmentStateChanged(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ sender, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachmentStateChangedEventArgs^ args); + +private: + void UnregisterFromBus(); + + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; + + alljoyn_aboutlistener m_aboutListener; + + // Used to pass a pointer to this class to callbacks. + Platform::WeakReference* m_weak; +}; + +} } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2IntrospectionXml.xml b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2IntrospectionXml.xml new file mode 100644 index 0000000000..71c3a1dbd3 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2IntrospectionXml.xml @@ -0,0 +1,42 @@ + + + A secure onboarding interface + + + Interface version number + + + + The configuration state + + + + The last error code and error message + + + + Sends the personal AP information to the onboardee + + + + + + + Tells the onboardee to connect to the personal AP + + + + Tells the onboardee to disconnect from the personal AP + + + + Scans all the Wi-Fi access points in the onboardee's proximity + + + + + This signal is emitted when the connection attempt against the personal AP is completed + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj new file mode 100644 index 0000000000..d994b5e18e --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj @@ -0,0 +1,260 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {f70f17ca-13c9-4386-80cf-bac562425c16} + WindowsRuntimeComponent + Scenario2WinRTComponent + org.alljoyn.Onboarding + en-US + 14.0 + true + Windows Store + 10.0 + 10.0.10240.0 + 10.0.10240.0 + true + + + + DynamicLibrary + true + v140 + + + DynamicLibrary + true + v140 + + + DynamicLibrary + true + v140 + + + DynamicLibrary + false + true + v140 + true + + + DynamicLibrary + false + true + v140 + true + + + DynamicLibrary + false + true + v140 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + false + + + false + + + $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\shared + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions);QCC_OS_GROUP_WINDOWS + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj -Zm210 %(AdditionalOptions) + 28204 + + + Console + false + WindowsApp.lib;%(AdditionalDependencies);msajapi.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters new file mode 100644 index 0000000000..00ac637f66 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + b4947898-b9a0-45e2-804b-eda2a7e89237 + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.cpp new file mode 100644 index 0000000000..4b23b663b1 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.cpp @@ -0,0 +1,32 @@ +//********************************************************* +// +// 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. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#include "pch.h" diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.h new file mode 100644 index 0000000000..7fc73998b8 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.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. +// +//********************************************************* + +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Tool: AllJoynCodeGenerator.exe +// +// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn +// Visual Studio Extension in the Visual Studio Gallery. +// +// The generated code should be packaged in a Windows 10 C++/CX Runtime +// Component which can be consumed in any UWP-supported language using +// APIs that are available in Windows.Devices.AllJoyn. +// +// Using AllJoynCodeGenerator - Invoke the following command with a valid +// Introspection XML file and a writable output directory: +// AllJoynCodeGenerator -i -o +// +//----------------------------------------------------------------------------- +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "AllJoynHelpers.h" +#include "AllJoynBusObjectManager.h" + +#define PROJECT_NAMESPACE org::alljoyn::Onboarding + +#include "OnboardingStructures.h" +#include "TypeConversionHelpers.h" +#include "OnboardingMethodResults.h" +#include "OnboardingEventArgs.h" +#include "IOnboardingService.h" +#include "OnboardingSignals.h" +#include "OnboardingProducer.h" +#include "OnboardingWatcher.h" +#include "OnboardingConsumer.h" +#include "OnboardingServiceEventArgs.h" +#include "OnboardingServiceEventAdapter.h" \ No newline at end of file diff --git a/Samples/AllJoyn/ConsumerExperiences/README.md b/Samples/AllJoyn/ConsumerExperiences/README.md new file mode 100644 index 0000000000..1b52ae65bc --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/README.md @@ -0,0 +1,67 @@ + + +# AllJoyn Consumer Experiences Sample + +This sample demonstrates how to create an AllJoyn Windows Universal app using Code Generation with Introspection XML and Windows.Devices.AllJoyn. + +Specifically, this sample covers: + +**Scenario 1** +- Creating and launching a Secure AllJoyn Consumer. +- Implementing method call, property and signal from generated code. + +**Scenario 2** +- Discovering and connecting to an Onboardee's SoftAP. +- Implementing method calls to get an Onboardee's network scan, configuring an Onboardee with WiFi credentials etc. + +**Note** The Universal Windows samples require Visual Studio 2015 to build and Windows 10 to execute. + +To obtain information about Windows 10, go to [Windows 10](http://go.microsoft.com/fwlink/?LinkID=532421) + +To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422) + +## Related topics + +### Samples + +[AllJoyn Producer Experiences](http://go.microsoft.com/fwlink/p/?LinkId=534025) +[AllJoyn Consumer Experiences](http://go.microsoft.com/fwlink/p/?LinkID=534021) + +The AllSeen Alliance has samples in [Windows SDK](https://allseenalliance.org/developers/download) + +### Reference + +[MSDN Reference](https://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.alljoyn.aspx) +[AllJoyn Reference] (https://allseenalliance.org/developers/develop/api-reference) +[Troubleshooting AllJoyn blog](http://channel9.msdn.com/Blogs/Internet-of-Things-Blog/Troubleshooting-AllJoyn-with-Windows-10-Insider-Preview-Builds) + +## System requirements + +ARM, ARM64, x86, or amd64 system + +**Client:** Windows 10 + +**Server:** Windows Server 2016 Technical Preview + +**Phone:** Windows 10 + +## Build the sample + +1. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**. +2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the C# language. Double-click the Visual Studio 2015 Solution (.sln) file. +3. Set the active solution configuration and platform to the desired values under **Build** \> **Configuration Manager**. +4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**. + +## Run the sample + +The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it. + +### Deploying the sample + +- Select Build > Deploy Solution. + +### Deploying and running the sample + +- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or selectDebug > Start Without Debugging. \ No newline at end of file diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/AllJoynConsumerExperiences.csproj b/Samples/AllJoyn/ConsumerExperiences/cs/AllJoynConsumerExperiences.csproj new file mode 100644 index 0000000000..ba135b39a4 --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/AllJoynConsumerExperiences.csproj @@ -0,0 +1,191 @@ + + + + + Debug + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F} + AppContainerExe + Properties + AllJoynConsumerExperiences + AllJoynConsumerExperiences + en-US + UAP + 10.0.10240.0 + 10.0.10240.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UAP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + App.xaml.cs + App.xaml + + + MainPage.xaml.cs + MainPage.xaml + + + + + + + Scenario1.xaml + + + + Scenario2.xaml + + + + + + Designer + + + + + App.xaml + MSBuild:Compile + Designer + + + MainPage.xaml + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Styles\Styles.xaml + MSBuild:Compile + Designer + + + + + Properties\Default.rd.xml + + + 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 + + + + + {0a9e8245-5676-4b45-b34b-756927d85b3c} + Scenario1WinRTComponent + + + {f70f17ca-13c9-4386-80cf-bac562425c16} + Scenario2WinRTComponent + + + + 14.0 + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/AllJoynConsumerExperiences.sln b/Samples/AllJoyn/ConsumerExperiences/cs/AllJoynConsumerExperiences.sln new file mode 100644 index 0000000000..65514d9a2d --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/AllJoynConsumerExperiences.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AllJoynConsumerExperiences", "AllJoynConsumerExperiences.csproj", "{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Scenario1WinRTComponent", "..\..\Common\Scenario1WinRTComponent\Scenario1WinRTComponent.vcxproj", "{0A9E8245-5676-4B45-B34B-756927D85B3C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Scenario2WinRTComponent", "..\..\Common\Scenario2WinRTComponent\Scenario2WinRTComponent.vcxproj", "{F70F17CA-13C9-4386-80CF-BAC562425C16}" +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 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.ActiveCfg = Debug|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.Build.0 = Debug|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.Deploy.0 = Debug|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.ActiveCfg = Debug|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.Build.0 = Debug|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.Deploy.0 = Debug|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.ActiveCfg = Debug|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.Build.0 = Debug|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.Deploy.0 = Debug|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.ActiveCfg = Release|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.Build.0 = Release|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.Deploy.0 = Release|ARM + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.ActiveCfg = Release|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.Build.0 = Release|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.Deploy.0 = Release|x64 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.ActiveCfg = Release|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.Build.0 = Release|x86 + {DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.Deploy.0 = Release|x86 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Debug|ARM.ActiveCfg = Debug|ARM + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Debug|ARM.Build.0 = Debug|ARM + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Debug|x64.ActiveCfg = Debug|x64 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Debug|x64.Build.0 = Debug|x64 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Debug|x86.ActiveCfg = Debug|Win32 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Debug|x86.Build.0 = Debug|Win32 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Release|ARM.ActiveCfg = Release|ARM + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Release|ARM.Build.0 = Release|ARM + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Release|x64.ActiveCfg = Release|x64 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Release|x64.Build.0 = Release|x64 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Release|x86.ActiveCfg = Release|Win32 + {0A9E8245-5676-4B45-B34B-756927D85B3C}.Release|x86.Build.0 = Release|Win32 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Debug|ARM.ActiveCfg = Debug|ARM + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Debug|ARM.Build.0 = Debug|ARM + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Debug|x64.ActiveCfg = Debug|x64 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Debug|x64.Build.0 = Debug|x64 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Debug|x86.ActiveCfg = Debug|Win32 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Debug|x86.Build.0 = Debug|Win32 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Release|ARM.ActiveCfg = Release|ARM + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Release|ARM.Build.0 = Release|ARM + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Release|x64.ActiveCfg = Release|x64 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Release|x64.Build.0 = Release|x64 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Release|x86.ActiveCfg = Release|Win32 + {F70F17CA-13C9-4386-80CF-BAC562425C16}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/OnboardingEnumTypes.cs b/Samples/AllJoyn/ConsumerExperiences/cs/OnboardingEnumTypes.cs new file mode 100644 index 0000000000..b214c150a2 --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/OnboardingEnumTypes.cs @@ -0,0 +1,70 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using Windows.UI.Xaml.Data; + +namespace AllJoynConsumerExperiences +{ + // All the Enums below as per the Onboarding interface spec + // For more info: https://allseenalliance.org/developers/learn/base-services/onboarding/interface + + enum OnboardingAuthenticationType + { + Wpa2Auto = -3, + WpaAuto = -2, + Any = -1, + Open = 0, + Wep = 1, + WpaTkip = 2, + WpaCcmp = 3, + Wpa2Tkip = 4, + Wpa2Ccmp = 5, + Wps = 6, + } + + enum ConfigureWiFiResultStatus + { + NonConcurrent = 1, + Concurrent = 2, + } + + enum ConnectionResultCode + { + Validated = 0, + Unreachable, + UnsupportedProtocol, + Unauthorized, + ErrorMessage, + } + + public class AuthTypeToStringConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + return value.ToString(); + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + OnboardingAuthenticationType returnValue; + + if (Enum.TryParse(value.ToString(), true, out returnValue)) + { + return returnValue; + } + else + { + return OnboardingAuthenticationType.Any; + } + } + } +} diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/Package.appxmanifest b/Samples/AllJoyn/ConsumerExperiences/cs/Package.appxmanifest new file mode 100644 index 0000000000..aed24af52f --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/Package.appxmanifest @@ -0,0 +1,55 @@ + + + + + + + + + + + AllJoyn Consumer Experiences C# Sample + Microsoft Corporation + Assets\StoreLogo-sdk.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/Properties/AssemblyInfo.cs b/Samples/AllJoyn/ConsumerExperiences/cs/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..2aa975602b --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/Properties/AssemblyInfo.cs @@ -0,0 +1,25 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("AllJoyn Consumer Experiences")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SDK Sample")] +[assembly: AssemblyCopyright("Copyright (c) Microsoft. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/RelayCommand.cs b/Samples/AllJoyn/ConsumerExperiences/cs/RelayCommand.cs new file mode 100644 index 0000000000..5301fd7e49 --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/RelayCommand.cs @@ -0,0 +1,56 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using System; +using System.Windows.Input; + +namespace AllJoynConsumerExperiences +{ + /// + /// Helpful class to execute the command logic (as defined by ViewModel's exposed ICommand properties) via delegates. + /// + public class RelayCommand : ICommand + { + readonly Action execute; + readonly Predicate canExecute; + + public RelayCommand(Action execute) + : this(execute, null) + { + } + + public event EventHandler CanExecuteChanged + { + add { } + remove { } + } + + public RelayCommand(Action execute, Predicate canExecute) + { + if (execute == null) + { + throw new ArgumentNullException("execute"); + } + this.execute = execute; + this.canExecute = canExecute; + } + + public bool CanExecute(object parameter) + { + return canExecute == null ? true : canExecute(parameter); + } + + public void Execute(object parameter) + { + execute(parameter); + } + } +} diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/SampleConfiguration.cs b/Samples/AllJoyn/ConsumerExperiences/cs/SampleConfiguration.cs new file mode 100644 index 0000000000..f66f646b5d --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/SampleConfiguration.cs @@ -0,0 +1,35 @@ +//********************************************************* +// +// 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. +// +//********************************************************* + +using AllJoynConsumerExperiences; +using System; +using System.Collections.Generic; +using Windows.UI.Xaml.Controls; + +namespace SDKTemplate +{ + public partial class MainPage : Page + { + public const string FEATURE_NAME = "AllJoyn Consumer Experiences"; + + List scenarios = new List + { + new Scenario() { Title="Secure Consumer", ClassType=typeof(Scenario1)}, + new Scenario() { Title="Onboarding Consumer", ClassType=typeof(Scenario2)} + }; + } + + public class Scenario + { + public string Title { get; set; } + public Type ClassType { get; set; } + } +} diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1.xaml b/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1.xaml new file mode 100644 index 0000000000..ca8d354eb3 --- /dev/null +++ b/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1.xaml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Secure Consumer will use About to find a Secure Producer and then make a call to the "Concatenate" method. + + + + + +