Tag Archives: API

How to Restart your App Programmatically

For some apps (especially games) it is not uncommon for the app to get into a state where it needs to restart – perhaps after a license update, after installing downloadable content, its caches have become corrupt or unwieldy, or for any other reason where the app needs to refresh state from scratch. In earlier releases, your only option would have been to prompt the user to close and relaunch, or to call CoreApplication.Exit – and both options provide sub-optimal user experience.

We have therefore introduced a new API that enables an app to request immediate termination and restart, and to pass arbitrary arguments into the fresh instance. In this post, we’ll look at how this works and how you can build it into your app. This is available now in Insider builds from Build 16226 onwards, along with the corresponding SDK.

Here’s a sample app, called TestRestart. 

The app provides a ListView of cities on the left, the currently-selected city on the right and a TextBox for providing arguments to the app when it is restarted. When the user taps the Request Restart button, the app will terminate and restart itself, passing in the supplied arguments. The new API, RequestRestartAsync, is exposed as a static method on the CoreApplication object. It takes a string parameter, which can be any string value you like – including input from the user or another external entity. If you do choose to accept input in this way, it is your responsibility to validate it correctly to make sure it conforms to whatever constraints you choose to impose. You should do this validation on input, before passing it to RequestRestartAsync. In this sample app, we’re expecting the user to type in the name of a city.


async private void DoRestartRequest()
{
    bool isValidPayload = false;
    string payload = restartArgs.Text;
    if (!string.IsNullOrEmpty(payload))
    {
        foreach (ImageViewModel imageItem in imageListView.Items)
        {
            if (imageItem.Name == payload)
            {
                isValidPayload = true;
                break;
            }
        }
    }

    if (isValidPayload)
    {
        AppRestartFailureReason result =
            await CoreApplication.RequestRestartAsync(payload);
        if (result == AppRestartFailureReason.NotInForeground ||
            result == AppRestartFailureReason.RestartPending ||
            result == AppRestartFailureReason.Other)
        {
            Debug.WriteLine("RequestRestartAsync failed: {0}", result);
        }
    }
}

To mitigate privacy concerns, an app is only permitted to restart itself if it is in the foreground at the time it makes the request. When the app restarts, it restarts with normal UI – that is, as a normal foreground window. If we were to permit a background task or minimized app to restart, the result would be unexpected to the user. This is why the API is framed as a request. If the request is denied, the app would need to handle the failure – perhaps by waiting until it is in the foreground and trying again. If you were to request a restart and then through some twist of logic managed to request it again before the system started the operation, then you’d get the RestartPending result, although this is an edge case. You’re unlikely to ever get the other result – unless something goes wrong in the platform.

Note that this is the only significant constraint, but you should use this API carefully. For example, you probably should not use it if your app was not originally launched by the user – for example, if it was launched as the result of a share or picker operation. Restarting in the middle of one of those contract operations would certainly confuse the user.

If the request is granted, the app is terminated and then restarted. There are many different ways to activate an app: in addition to a regular launch activation, apps can choose to support file activation, protocol activation, share or picker activation and so on. The list is documented here. For the restart case, the app will be activated as a regular launch – just as if the user had closed the app manually and tapped its tile to launch it again – but including the arbitrary arguments supplied earlier (if any).

In your App class, you should handle this by overriding the OnActivated method. Test the ActivationKind, and if it’s ActivationKind.Launch, then the incoming IActivatedEventArgs will be a LaunchActivatedEventArgs. From this, you can get hold of the incoming activation arguments. For a regular user-initiated launch, the Arguments will be empty, so if it’s not empty you could simply infer that this is a restart activation. You can also check the PreviousExecutionState, which for a restart operation will be set to Terminated.

Although the arguments might have originated from an untrusted source (eg, the user), you should have done the validation before requesting restart. If so, you can consider them trustworthy when you receive them in OnActivated.


protected override void OnActivated(IActivatedEventArgs args)
{
    switch (args.Kind)
    {
        case ActivationKind.Launch:
            LaunchActivatedEventArgs launchArgs = args as LaunchActivatedEventArgs;
            string argString = launchArgs.Arguments;

            Frame rootFrame = Window.Current.Content as Frame;
            if (rootFrame == null)
            {
                rootFrame = new Frame();
                Window.Current.Content = rootFrame;
            }
            rootFrame.Navigate(typeof(MainPage), argString);
            Window.Current.Activate();
            break;
    }
}

What you do with the incoming arguments is entirely up to you. In this app, we’re simply passing them on to the MainPage. In the MainPage in turn, we have an override of OnNavigatedTo which uses the string to select an item in the ListView:


protected override void OnNavigatedTo(NavigationEventArgs e)

{
    string payload = e.Parameter as string;
    if (!string.IsNullOrEmpty(payload))
    {
        foreach (ImageViewModel imageItem in imageListView.Items)
        {
            if (imageItem.Name == payload)
            {
                imageListView.SelectedItem = imageItem;
                break;
            }
        }
    }
}

As you can see, the CoreApplication.RequestRestartAsync method is a simple API. You can use it to terminate your app immediately, and have it restart as if by user action, with the additional option of passing in arbitrary arguments on activation.

Sample Code here.

Dev Projects for the Long Weekend

Find your favorite chair, kick your feet up and grab yourself a cup of coffee. It’s finally time to pick up some of the dev projects you’ve been eyeballing from behind the hazy fog of pre-vacation deadlines.

For the long weekend, we’ve assembled a quick list of three projects we’ll be working on between family time and scouring Stack Overflow for answers to life’s questions. Take a look below to get started!

IoT for the Whole Family

IoT projects can be both fun and practical – take a look at a few of our favorite selections below. After securing your home with an IoT Security Camera and automating the rest of your house, you might really need to think about rewarding yourself with that automated Kegerator. Just saying.

Explore the Devices and Sensors GitHub Library

Thirty-five samples to work with right here, folks! With these samples, you can get familiar with the API usage patterns that make the UWP unique. This section has code samples for accelerometers, relative inclinometers and pretty much everything in between.

Dive into Microsoft Open Source Code

We’re still reeling in the excitement about our partnership with the Linux Foundation and the steps we’re taking to make the UWP an increasingly open platform. Take a look at our existing Open Source projects over on Github to see how you can get started.

And that’s all! Have a great long weekend and remember to tweet us if you have any questions or comments!

Download Visual Studio to get started.

The Windows team would love to hear your feedback.  Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.

Windows 10 SDK Preview Build 14965 Released

Today, we released a new Windows 10 Anniversary SDK Preview to be used in conjunction with Windows 10 Insider Preview (Build 14965 or greater). The Preview SDK is a pre-release and cannot be used in a production environment. Please only install the SDK on your test machine. The Preview SDK Build 14965 contains bug fixes and under development changes to the API surface area. If you are working on an application that you need to submit to the store, you should not install the preview.

The Preview SDK can be downloaded from the developer section on Windows Insider.

For feedback and updates to the known issues, please see the developer forum.  For new feature requests, head over to our Windows Platform UserVoice.

Things to note:

What’s New

Known Issues Windows SDK

  • Wrong GenXBF.DLL
    If you installed a previous Windows SDK flight, either version 14951 or 14931, you may have an incorrect GenXBF.dll installed. Please follow the following steps after installing the Windows 10 SDK Preview build 14965.
  1. Exit Visual Studio
  2. Open an Administrative command prompt
  3. Type the following:

    DEL “c:Program Files (x86)Windows Kits10binx86genxbf.dll”

    DEL “c:Program Files (x86)Windows Kits10binx64genxbf.dll”

  1. Run Control Panel
  2. Select Uninstall a Program
  3. Highlight Windows Software Development Kit – Windows 10.0.14965.1000
  4. Click Change
  5. Select Repair
  6. Click Next

Windows SDK setup will restore the missing GenXBF.dlls  with the appropriate version.

  • Visual Studio 2017 fails with HRESULT: 0x80041FE2 when trying to create C++ UWP apps targeting build 14965 SDK

This is a known problem. Here are steps to address this issue in your project file:

  1. Close the project
  2. Open up the project file in notepad or your favorite editor
  3. Add the following to the project file:
      <PropertyGroup><DoBundleInstallationChecks>false</DoBundleInstallationChecks></PropertyGroup>
  4. Reopen the project in Visual Studio

Known Issues Microsoft Emulator

Microsoft Emulator Preview for Windows 10 Mobile (10.0.14965.0) crashes when launching

Impact:

Please note that there is a bug impacting the usage of hardware accelerated graphics in the latest release of the Mobile Emulator. Follow the instructions below to temporarily disable hardware accelerated graphics in the emulator and use the emulator with software rendered graphics (WARP).

NOTE: The following registry setting will impact any and all Microsoft Emulators installed on your machine. You will need to remove this registry setting in order to re-enable hardware accelerated graphics in the emulator.

  1. Create the following registry subkey if it doesn’t exist: HKEY_LOCAL_MACHINESOFTWAREWow6432NodeMicrosoftXde10.0
  2. Right click the 10.0 folder, point to New, and then click DWORD Value.
  3. Type DisableRemoteFx, and then press Enter.
  4. Double-click DisableRemoteFx, enter 1 in the Value data box, select the Decimal option, and then click OK.

API Updates and Additions

The following API changes are under development and new or updated for this release of the SDK.

namespace Windows.ApplicationModel.Preview.Notes {
  public sealed class NotesWindowManagerPreview {
    void SetFocusToPreviousView();
    IAsyncAction SetThumbnailImageForTaskSwitcherAsync(SoftwareBitmap bitmap);
    void ShowNoteRelativeTo(int noteViewId, int anchorNoteViewId, NotesWindowManagerPreviewShowNoteOptions options);
    void ShowNoteWithPlacement(int noteViewId, IBuffer data, NotesWindowManagerPreviewShowNoteOptions options);
  }
  public sealed class NotesWindowManagerPreviewShowNoteOptions
}
 
namespace Windows.Devices.Gpio {
  public sealed class GpioInterruptBuffer
  public struct GpioInterruptEvent
  public enum GpioOpenStatus {
    MuxingConflict = 3,
    UnknownError = 4,
  }
  public sealed class GpioPin : IClosable {
    GpioInterruptBuffer InterruptBuffer { get; }
    ulong InterruptCount { get; }
    void CreateInterruptBuffer();
    void CreateInterruptBuffer(int minimumCapacity);
    void StartInterruptBuffer();
    void StartInterruptBuffer(GpioPinEdge edge);
    void StartInterruptCount();
    void StartInterruptCount(GpioPinEdge edge);
    void StopInterruptBuffer();
    void StopInterruptCount();
  }
}
namespace Windows.Devices.Gpio.Provider {
  public interface IGpioInterruptBufferProvider
  public interface IGpioPinProvider2
  public struct ProviderGpioInterruptEvent
}
namespace Windows.Devices.I2c {
  public enum I2cTransferStatus {
    ClockStretchTimeout = 3,
    UnknownError = 4,
  }
}
 
namespace Windows.ApplicationModel {
  public sealed class Package {
    IAsyncOperation<PackageContentGroup> GetContentGroupAsync(string name);
    IAsyncOperation<IVector<PackageContentGroup>> GetContentGroupsAsync();
    IAsyncOperation<bool> SetInUseAsync(bool inUse);
    IAsyncOperation<IVector<PackageContentGroup>> StageContentGroupsAsync(IIterable<string> names);
    IAsyncOperation<IVector<PackageContentGroup>> StageContentGroupsAsync(IIterable<string> names, bool moveToHeadOfQueue);
  }
  public sealed class PackageCatalog {
    event TypedEventHandler<PackageCatalog, PackageContentGroupStagingEventArgs> PackageContentGroupStaging;
    IAsyncOperation<Package> AddOptionalPackageAsync(string optionalPackageFamilyName);
  }
  public sealed class PackageContentGroup
  public sealed class PackageContentGroupStagingEventArgs
  public enum PackageContentGroupState
}
namespace Windows.ApplicationModel.Activation {
  public enum ActivationKind {
    ContactPanel = 1017,
    LockScreenComponent = 1016,
  }
  public sealed class ContactPanelActivatedEventArgs : IActivatedEventArgs, IActivatedEventArgsWithUser, IContactPanelActivatedEventArgs
  public interface IContactPanelActivatedEventArgs
  public sealed class LockScreenComponentActivatedEventArgs : IActivatedEventArgs
  public sealed class ToastNotificationActivatedEventArgs : IActivatedEventArgs, IActivatedEventArgsWithUser, IApplicationViewActivatedEventArgs, IToastNotificationActivatedEventArgs {
    int CurrentlyShownApplicationViewId { get; }
  }
}
namespace Windows.ApplicationModel.Background {
  public sealed class GattCharacteristicNotificationTrigger : IBackgroundTrigger {
    public GattCharacteristicNotificationTrigger(GattCharacteristic characteristic, BluetoothEventTriggeringMode eventTriggeringMode);
    BluetoothEventTriggeringMode EventTriggeringMode { get; }
  }
  public sealed class GattServiceProviderTrigger : IBackgroundTrigger
}
namespace Windows.ApplicationModel.Contacts {
  public sealed class ContactAnnotation {
    string ContactGroupId { get; set; }
    string ContactListId { get; set; }
  }
  public enum ContactAnnotationOperations : uint {
    Share = (uint)32,
  }
  public sealed class ContactAnnotationStore {
    IAsyncOperation<IVectorView<ContactAnnotation>> FindAnnotationsForContactGroupAsync(string contactGroupId);
    IAsyncOperation<IVectorView<ContactAnnotation>> FindAnnotationsForContactListAsync(string contactListId);
  }
  public sealed class ContactGroup
  public sealed class ContactGroupMember
  public sealed class ContactGroupMemberBatch
  public sealed class ContactGroupMemberReader
  public enum ContactGroupOtherAppReadAccess
  public static class ContactManager {
    public static IAsyncOperation<bool> IsShowFullContactCardSupportedAsync();
  }
  public sealed class ContactManagerForUser {
    void ShowFullContactCard(Contact contact, FullContactCardOptions fullContactCardOptions);
  }
  public sealed class ContactPanel
  public sealed class ContactPanelClosingEventArgs
  public sealed class ContactPanelLaunchFullAppRequestedEventArgs
  public sealed class ContactPicker {
    User User { get; }
    public static ContactPicker CreateForUser(User user);
    public static IAsyncOperation<bool> IsSupportedAsync();
  }
  public sealed class ContactStore {
    IAsyncOperation<ContactGroup> CreateContactGroupAsync(string displayName);
    IAsyncOperation<ContactGroup> CreateContactGroupAsync(string displayName, string userDataAccountId);
    IAsyncOperation<IVectorView<ContactGroup>> FindContactGroupsAsync();
    IAsyncOperation<IVectorView<ContactGroup>> FindContactGroupsByRemoteIdAsync(string remoteId);
    IAsyncOperation<ContactGroup> GetContactGroupAsync(string contactGroupId);
  }
  public sealed class PinnedContactIdsQueryResult
  public sealed class PinnedContactManager
  public enum PinnedContactSurface
}
namespace Windows.ApplicationModel.Core {
  public sealed class CoreApplicationView {
    IPropertySet Properties { get; }
  }
}
namespace Windows.ApplicationModel.DataTransfer {
  public sealed class DataTransferManager {
    public static void ShowShareUI(ShareUIOptions shareOptions);
  }
  public sealed class ShareUIOptions
}
namespace Windows.ApplicationModel.Email {
  public sealed class EmailMessage {
    IVector<EmailRecipient> ReplyTo { get; }
    EmailRecipient SentRepresenting { get; set; }
  }
}
namespace Windows.ApplicationModel.Store.LicenseManagement {
  public static class LicenseManager {
    public static IAsyncAction RefreshLicensesAsync(LicenseRefreshOption refreshOption);
  }
  public enum LicenseRefreshOption
}
namespace Windows.ApplicationModel.UserDataAccounts {
  public sealed class UserDataAccount {
    bool CanShowCreateContactGroup { get; set; }
    bool IsProtectedUnderLock { get; set; }
    IPropertySet ProviderProperties { get; }
    IAsyncOperation<IVectorView<ContactGroup>> FindContactGroupsAsync();
    IAsyncOperation<IVectorView<UserDataTaskList>> FindUserDataTaskListsAsync();
    IAsyncOperation<string> TryShowCreateContactGroupAsync();
  }
  public sealed class UserDataAccountStore {
    IAsyncOperation<UserDataAccount> CreateAccountAsync(string userDisplayName, string packageRelativeAppId, string enterpriseId);
  }
}
namespace Windows.ApplicationModel.UserDataTasks {
  public sealed class UserDataTask
  public sealed class UserDataTaskBatch
  public enum UserDataTaskDaysOfWeek : uint
  public enum UserDataTaskDetailsKind
  public enum UserDataTaskKind
  public sealed class UserDataTaskList
  public sealed class UserDataTaskListLimitedWriteOperations
  public enum UserDataTaskListOtherAppReadAccess
  public enum UserDataTaskListOtherAppWriteAccess
  public sealed class UserDataTaskListSyncManager
  public enum UserDataTaskListSyncStatus
  public static class UserDataTaskManager
  public sealed class UserDataTaskManagerForUser
  public enum UserDataTaskPriority
  public enum UserDataTaskQueryKind
  public sealed class UserDataTaskQueryOptions
  public enum UserDataTaskQuerySortProperty
  public sealed class UserDataTaskReader
  public sealed class UserDataTaskRecurrenceProperties
  public enum UserDataTaskRecurrenceUnit
  public sealed class UserDataTaskRegenerationProperties
  public enum UserDataTaskRegenerationUnit
  public enum UserDataTaskSensitivity
  public sealed class UserDataTaskStore
  public enum UserDataTaskStoreAccessType
  public enum UserDataTaskWeekOfMonth
}
namespace Windows.ApplicationModel.UserDataTasks.DataProvider {
  public sealed class UserDataTaskDataProviderConnection
  public sealed class UserDataTaskDataProviderTriggerDetails
  public sealed class UserDataTaskListCompleteTaskRequest
  public sealed class UserDataTaskListCompleteTaskRequestEventArgs
  public sealed class UserDataTaskListCreateOrUpdateTaskRequest
  public sealed class UserDataTaskListCreateOrUpdateTaskRequestEventArgs
  public sealed class UserDataTaskListDeleteTaskRequest
  public sealed class UserDataTaskListDeleteTaskRequestEventArgs
  public sealed class UserDataTaskListSkipOccurrenceRequest
  public sealed class UserDataTaskListSkipOccurrenceRequestEventArgs
  public sealed class UserDataTaskListSyncManagerSyncRequest
  public sealed class UserDataTaskListSyncManagerSyncRequestEventArgs
}
namespace Windows.Gaming.Input {
  public sealed class FlightStick : IGameController
  public enum FlightStickButtons : uint
  public struct FlightStickReading
  public enum GameControllerSwitchKind
  public enum GameControllerSwitchPosition
  public sealed class RawGameController : IGameController
}
namespace Windows.Gaming.Input.Custom {
  public sealed class HidGameControllerProvider : IGameControllerProvider
  public interface IHidGameControllerInputSink : IGameControllerInputSink
}
namespace Windows.Graphics.Printing.PrintTicket {
  public interface IPrintTicketSchemaDisplayableElement : IPrintTicketSchemaElement
  public interface IPrintTicketSchemaElement
  public interface IPrintTicketSchemaOption : IPrintTicketSchemaDisplayableElement, IPrintTicketSchemaElement
  public interface IPrintTicketSchemaParameterDefinition : IPrintTicketSchemaElement
  public interface IPrintTicketSchemaValue
  public sealed class PrintTicketSchemaCapabilities : IPrintTicketSchemaElement
  public sealed class PrintTicketSchemaFeature : IPrintTicketSchemaDisplayableElement, IPrintTicketSchemaElement
  public sealed class PrintTicketSchemaParameterInitializer : IPrintTicketSchemaElement
  public enum tagSchemaParameterDataType
  public enum tagSchemaSelectionType
  public enum tagValueType
  public sealed class WorkflowPrintSchemaTicket : IPrintTicketSchemaElement
  public sealed class XmlNode
}
namespace Windows.Graphics.Printing.Workflow {
  public interface IPrinterPropertyBag
  public sealed class PrinterQueue
  public sealed class PrintTaskBackgroundSessionManager
  public sealed class PrintTaskConfig
  public sealed class PrintTaskForegroundSessionManager
  public sealed class PrintTaskSessionState
  public enum PrintTaskSessionStatus
  public sealed class PrintTaskSetupEventArgs
  public sealed class PrintTaskSubmissionController
  public sealed class PrintTaskSubmittedEventArgs
  public sealed class PrintTaskTarget
  public sealed class PrintTaskUIActivatedEventArgs : IActivatedEventArgs
  public sealed class PrintTaskXpsDataAvailableEventArgs
  public sealed class SourceContent
  public sealed class SpoolStreamContent
  public sealed class StreamTarget
  public sealed class WorkflowTaskContext
  public sealed class WorkflowTriggerDetails
  public sealed class XpsOmContent
  public sealed class XpsOmReceiver
}
namespace Windows.Management.Deployment {
  public enum DeploymentOptions : uint {
    EnableStreamedInstall = (uint)128,
    RequiredContentGroupOnly = (uint)256,
  }
  public sealed class PackageManager {
    IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> AddPackageAsync(Uri packageUri, IIterable<Uri> dependencyPackageUris, DeploymentOptions deploymentOptions, PackageVolume targetVolume, IIterable<string> optionalPackageFamilyNames, IIterable<Uri> externalPackageUris);
    IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> RegisterPackageByFamilyNameAsync(string mainPackageFamilyName, IIterable<string> dependencyPackageFamilyNames, DeploymentOptions deploymentOptions, PackageVolume appDataVolume, IIterable<string> optionalPackageFamilyNames);
    IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> StagePackageAsync(Uri packageUri, IIterable<Uri> dependencyPackageUris, DeploymentOptions deploymentOptions, PackageVolume targetVolume, IIterable<string> optionalPackageFamilyNames, IIterable<Uri> externalPackageUris);
  }
}
namespace Windows.Management.Policies {
  public sealed class BinaryPolicy
  public sealed class BooleanPolicy
  public static class BrowserPolicies
  public sealed class BrowserPoliciesForUser
  public sealed class Int32Policy
  public sealed class StringPolicy
}
namespace Windows.Media {
  public sealed class MediaExtensionManager {
    void RegisterMediaExtensionForAppService(IMediaExtension extension, AppServiceConnection connection);
  }
  public sealed class MediaMarkerSpeechSentenceBoundary : IMediaMarker
  public sealed class MediaMarkerSpeechWordBoundary : IMediaMarker
  public static class MediaMarkerTypes {
    public static string SentenceBoundary { get; }
    public static string WordBoundary { get; }
  }
  public struct MediaTimeRange
}
namespace Windows.Media.Capture {
  public sealed class MediaCaptureInitializationSettings {
    bool AlwaysPlaySystemShutterSound { get; set; }
  }
}
namespace Windows.Media.Core {
  public sealed class ChapterCue : IMediaCue
  public sealed class DataCue : IMediaCue {
    PropertySet Properties { get; }
  }
  public sealed class ImageCue : IMediaCue
  public sealed class MediaBindingEventArgs {
    void SetAdaptiveMediaSource(AdaptiveMediaSource mediaSource);
    void SetStorageFile(IStorageFile file);
  }
  public sealed class MediaSource : IClosable, IMediaPlaybackSource {
    AdaptiveMediaSource AdaptiveMediaSource { get; }
    MediaStreamSource MediaStreamSource { get; }
    MseStreamSource MseStreamSource { get; }
    Uri Uri { get; }
  }
  public sealed class MediaStreamSource : IMediaSource {
    IReference<double> MaxSupportedPlaybackRate { get; set; }
  }
  public enum TimedMetadataKind {
    ImageSubtitle = 6,
  }
  public enum TimedTextFontStyle
  public sealed class TimedTextSource {
    public static TimedTextSource CreateFromStreamWithIndex(IRandomAccessStream stream, IRandomAccessStream indexStream);
    public static TimedTextSource CreateFromStreamWithIndex(IRandomAccessStream stream, IRandomAccessStream indexStream, string defaultLanguage);
    public static TimedTextSource CreateFromUriWithIndex(Uri uri, Uri indexUri);
    public static TimedTextSource CreateFromUriWithIndex(Uri uri, Uri indexUri, string defaultLanguage);
  }
  public sealed class TimedTextStyle {
    TimedTextFontStyle FontStyle { get; set; }
    bool IsLineThroughEnabled { get; set; }
    bool IsOverlineEnabled { get; set; }
    bool IsUnderlineEnabled { get; set; }
  }
}
namespace Windows.Media.Core.Preview {
  public static class SoundLevelBroker
}
namespace Windows.Media.MediaProperties {
  public static class MediaEncodingSubtypes {
    public static string D16 { get; }
    public static string L16 { get; }
    public static string L8 { get; }
    public static string Vp9 { get; }
  }
  public enum SphericalVideoFrameFormat
  public sealed class VideoEncodingProperties : IMediaEncodingProperties {
    SphericalVideoFrameFormat SphericalVideoFrameFormat { get; }
  }
}
namespace Windows.Media.Playback {
  public enum AutoLoadedDisplayPropertyKind
  public sealed class CurrentMediaPlaybackItemChangedEventArgs {
    MediaPlaybackItemChangedReason Reason { get; }
  }
  public sealed class MediaPlaybackItem : IMediaPlaybackSource {
    AutoLoadedDisplayPropertyKind AutoLoadedDisplayProperties { get; set; }
    bool IsDisabledInPlaybackList { get; set; }
    double TotalDownloadProgress { get; }
  }
  public enum MediaPlaybackItemChangedReason
  public sealed class MediaPlaybackList : IMediaPlaybackSource {
    IReference<uint> MaxPlayedItemsToKeepOpen { get; set; }
  }
  public sealed class MediaPlaybackSession {
    bool IsMirroring { get; set; }
    MediaPlaybackSphericalVideoProjection SphericalVideoProjection { get; }
    event TypedEventHandler<MediaPlaybackSession, object> BufferedRangesChanged;
    event TypedEventHandler<MediaPlaybackSession, object> PlayedRangesChanged;
    event TypedEventHandler<MediaPlaybackSession, object> SeekableRangesChanged;
    event TypedEventHandler<MediaPlaybackSession, object> SupportedPlaybackRatesChanged;
    IVectorView<MediaTimeRange> GetBufferedRanges();
    IVectorView<MediaTimeRange> GetPlayedRanges();
    IVectorView<MediaTimeRange> GetSeekableRanges();
    bool IsSupportedPlaybackRateRange(double rate1, double rate2);
  }
  public sealed class MediaPlaybackSphericalVideoProjection
}
namespace Windows.Media.Protection.PlayReady {
  public interface IPlayReadyLicenseSession2 : IPlayReadyLicenseSession
  public sealed class PlayReadyLicense : IPlayReadyLicense {
    bool ExpiresInRealTime { get; }
    bool InMemoryOnly { get; }
    Guid SecureStopId { get; }
    uint SecurityLevel { get; }
  }
  public sealed class PlayReadyLicenseAcquisitionServiceRequest : IMediaProtectionServiceRequest, IPlayReadyLicenseAcquisitionServiceRequest, IPlayReadyServiceRequest {
    PlayReadyLicenseIterable CreateLicenseIterable(PlayReadyContentHeader contentHeader, bool fullyEvaluated);
  }
  public sealed class PlayReadyLicenseSession : IPlayReadyLicenseSession, IPlayReadyLicenseSession2 {
    PlayReadyLicenseIterable CreateLicenseIterable(PlayReadyContentHeader contentHeader, bool fullyEvaluated);
  }
}
namespace Windows.Media.SpeechSynthesis {
  public sealed class SpeechSynthesisOptions
  public sealed class SpeechSynthesizer : IClosable {
    SpeechSynthesisOptions Options { get; }
  }
}
namespace Windows.Media.Streaming.Adaptive {
  public sealed class AdaptiveMediaSource : IClosable, IMediaSource {
    IReference<TimeSpan> DesiredSeekableWindowSize { get; set; }
    AdaptiveMediaSourceDiagnostics Diagnostics { get; }
    IReference<TimeSpan> MaxSeekableWindowSize { get; }
    IReference<TimeSpan> MinLiveOffset { get; }
    void Close();
    AdaptiveMediaSourceCorrelatedTimes GetCorrelatedTimes();
  }
  public sealed class AdaptiveMediaSourceCorrelatedTimes
  public sealed class AdaptiveMediaSourceDiagnosticAvailableEventArgs
  public sealed class AdaptiveMediaSourceDiagnostics
  public enum AdaptiveMediaSourceDiagnosticType
  public sealed class AdaptiveMediaSourceDownloadBitrateChangedEventArgs {
    AdaptiveMediaSourceDownloadBitrateChangedReason Reason { get; }
  }
  public enum AdaptiveMediaSourceDownloadBitrateChangedReason
}
namespace Windows.Networking.NetworkOperators {
  public sealed class MobileBroadbandAccount {
    Uri AccountExperienceUrl { get; }
  }
  public sealed class MobileBroadbandDeviceInformation {
    string SimGid1 { get; }
    string SimPnn { get; }
    string SimSpn { get; }
  }
}
namespace Windows.Payments {
  public interface IPaymentItem
  public sealed class PaymentAddress
  public static class PaymentAppRegistration
  public sealed class PaymentCurrencyAmount
  public sealed class PaymentDetails
  public sealed class PaymentDetailsModifier
  public sealed class PaymentItem : IPaymentItem
  public static class PaymentMediator
  public sealed class PaymentMerchantInfo
  public sealed class PaymentMethodData
  public enum PaymentOptionPresence
  public sealed class PaymentOptions
  public sealed class PaymentRequest
  public sealed class PaymentRequestChangedEventArgs
  public delegate IAsyncOperation<PaymentRequestChangedEventResult> PaymentRequestChangedEventHandler(PaymentRequest paymentRequest, PaymentRequestChangedEventArgs args);
  public sealed class PaymentRequestChangedEventResult
  public enum PaymentRequestChangeSource
  public enum PaymentRequestCompletionStatus
  public enum PaymentRequestStatus
  public sealed class PaymentRequestSubmitResult
  public sealed class PaymentResponse
  public sealed class PaymentShippingOption : IPaymentItem
  public sealed class PaymentToken
  public sealed class PaymentTransaction
  public sealed class PaymentTransactionAcceptResult
}
namespace Windows.Perception.Spatial.Preview {
  public interface ISpatialAnchorStorage
  public sealed class SpatialAnchorMetadata
  public enum SpatialAnchorStorageContentChange
  public sealed class SpatialAnchorStorageContentChangedEventArgs
  public sealed class SpatialElement
  public sealed class SpatialElementChangedEventArgs
  public sealed class SpatialElementStore
}
namespace Windows.Perception.Spatial.Preview.Sharing {
  public interface ISpatialSharingSession
  public interface ISpatialSharingSessionHost
  public interface ISpatialSharingSessionManager
  public sealed class SessionChangedEventArgs
  public sealed class SessionInviteReceivedEventArgs
  public sealed class SessionMessageReceivedEventArgs
  public sealed class SessionParticipantEventArgs
  public sealed class SessionParticipantLeftEventArgs
  public sealed class SpatialSharingDevice
  public sealed class SpatialSharingQueryResult
  public sealed class SpatialSharingSession : ISpatialAnchorStorage, ISpatialSharingSession
  public sealed class SpatialSharingSessionHost : ISpatialSharingSessionHost
  public sealed class SpatialSharingSessionInvite
  public sealed class SpatialSharingSessionManager : ISpatialSharingSessionManager
  public sealed class SpatialSharingSessionParticipant
  public enum SpatialSharingSessionState
  public sealed class SpatialSharingSessionToken
}
namespace Windows.Security.Cryptography.Certificates {
  public sealed class CertificateExtension
  public sealed class CertificateRequestProperties {
    IVector<CertificateExtension> Extensions { get; }
    SubjectAlternativeNameInfo SubjectAlternativeName { get; }
    IVector<string> SuppressedDefaults { get; }
  }
  public sealed class SubjectAlternativeNameInfo {
    IVector<string> DistinguishedNames { get; }
    IVector<string> DnsNames { get; }
    IVector<string> EmailNames { get; }
    CertificateExtension Extension { get; }
    IVector<string> IPAddresses { get; }
    IVector<string> PrincipalNames { get; }
    IVector<string> Urls { get; }
  }
}
namespace Windows.Services.Cortana {
  public enum CortanaPermission
  public enum CortanaPermissionsChangeResult
  public sealed class CortanaPermissionsManager
}
namespace Windows.Services.Maps {
  public sealed class EnhancedWaypoint
  public static class MapRouteFinder {
    public static IAsyncOperation<MapRouteFinderResult> GetDrivingRouteFromEnhancedWaypointsAsync(IIterable<EnhancedWaypoint> waypoints);
    public static IAsyncOperation<MapRouteFinderResult> GetDrivingRouteFromEnhancedWaypointsAsync(IIterable<EnhancedWaypoint> waypoints, MapRouteDrivingOptions options);
  }
  public static class MapService {
    public static MapServiceDataUsagePreference DataUsagePreference { get; set; }
  }
  public enum MapServiceDataUsagePreference
  public enum WaypointKind
}
namespace Windows.Services.Maps.OfflineMaps {
  public sealed class OfflineMapPackage
  public sealed class OfflineMapPackageQueryResult
  public enum OfflineMapPackageQueryStatus
  public sealed class OfflineMapPackageStartDownloadResult
  public enum OfflineMapPackageStartDownloadStatus
  public enum OfflineMapPackageStatus
}
namespace Windows.System {
  public sealed class DispatcherQueue
  public delegate void DispatcherQueueHandler();
  public delegate IAsyncAction DispatcherQueueHandlerAsync();
  public sealed class DispatcherQueueOptions
  public enum DispatcherQueuePriority
  public sealed class DispatcherQueueTimer
}
namespace Windows.System.Preview.RemoteSessions {
  public enum BinaryChannelTransportMode
  public sealed class RemoteSession
  public sealed class RemoteSessionAddedEventArgs
  public sealed class RemoteSessionBinaryChannel
  public sealed class RemoteSessionBinaryMessageReceivedEventArgs
  public enum RemoteSessionConnectionStatus
  public sealed class RemoteSessionConnectResult
  public sealed class RemoteSessionDisconnectedEventArgs
  public enum RemoteSessionDisconnectedReason
  public sealed class RemoteSessionInfo
  public sealed class RemoteSessionInvitationManager
  public sealed class RemoteSessionInvitationReceivedEventArgs
  public sealed class RemoteSessionJoinRequest
  public sealed class RemoteSessionJoinRequestedEventArgs
  public sealed class RemoteSessionParticipant
  public sealed class RemoteSessionParticipantChangedEventArgs
  public sealed class RemoteSessionRemovedEventArgs
  public sealed class RemoteSessionUpdatedEventArgs
  public sealed class RemoteSessionWatcher
}
namespace Windows.System.Profile {
  public static class EducationSettings
}
namespace Windows.System.RemoteSystems {
  public sealed class RemoteSystem {
    IAsyncOperation<bool> GetResourceAvailableAsync(string query);
  }
}
namespace Windows.System.RemoteSystems.Preview {
  public static class RemoteSystemResourceQuery
}
namespace Windows.UI.Composition {
  public class CompositionDrawingSurface : CompositionObject, ICompositionSurface {
  }
  public sealed class CompositionGraphicsDevice : CompositionObject {
    CompositionVirtualDrawingSurface CreateVirtualDrawingSurface(Size sizePixels, DirectXPixelFormat pixelFormat, DirectXAlphaMode alphaMode);
  }
  public sealed class CompositionVirtualDrawingSurface : CompositionDrawingSurface, ICompositionSurface
  public sealed class CompositionVisualSurface : CompositionObject, ICompositionSurface
  public sealed class CompositionWindowBackdropBrush : CompositionBrush
  public sealed class Compositor : IClosable {
    CompositionVisualSurface CreateVisualSurface();
    CompositionWindowBackdropBrush CreateWindowBackdropBrush();
  }
  public sealed class LayerVisual : ContainerVisual {
    CompositionShadow Shadow { get; set; }
  }
  public class Visual : CompositionObject {
    Vector3 RelativeOffset { get; set; }
    Vector2 RelativeSize { get; set; }
    Visual TransformParent { get; set; }
  }
}
namespace Windows.UI.Core {
  public sealed class CoreWindow : ICorePointerRedirector, ICoreWindow {
    event TypedEventHandler<CoreWindow, object> ResizeCompleted;
    event TypedEventHandler<CoreWindow, object> ResizeStarted;
  }
}
namespace Windows.UI.Input {
  public static class KnownSimpleHapticsControllerWaveforms
  public sealed class RadialController {
    event TypedEventHandler<RadialController, RadialControllerButtonHoldingEventArgs> ButtonHolding;
    event TypedEventHandler<RadialController, RadialControllerButtonPressedEventArgs> ButtonPressed;
    event TypedEventHandler<RadialController, RadialControllerButtonReleasedEventArgs> ButtonReleased;
  }
  public sealed class RadialControllerButtonClickedEventArgs {
    SimpleHapticsController SimpleHapticsController { get; }
  }
  public sealed class RadialControllerButtonHoldingEventArgs
  public sealed class RadialControllerButtonPressedEventArgs
  public sealed class RadialControllerButtonReleasedEventArgs
  public sealed class RadialControllerConfiguration {
    RadialController ActiveControllerWhenMenuIsSuppressed { get; set; }
    bool IsMenuSuppressed { get; set; }
  }
  public sealed class RadialControllerControlAcquiredEventArgs {
    bool IsButtonPressed { get; }
    SimpleHapticsController SimpleHapticsController { get; }
  }
  public sealed class RadialControllerMenuItem {
    public static RadialControllerMenuItem CreateFromFontGlyph(string displayText, string glyph, string fontFamily);
    public static RadialControllerMenuItem CreateFromFontGlyph(string displayText, string glyph, string fontFamily, Uri fontUri);
  }
  public sealed class RadialControllerRotationChangedEventArgs {
    bool IsButtonPressed { get; }
    SimpleHapticsController SimpleHapticsController { get; }
  }
  public sealed class RadialControllerScreenContactContinuedEventArgs {
    bool IsButtonPressed { get; }
    SimpleHapticsController SimpleHapticsController { get; }
  }
  public sealed class RadialControllerScreenContactEndedEventArgs
  public sealed class RadialControllerScreenContactStartedEventArgs {
    bool IsButtonPressed { get; }
    SimpleHapticsController SimpleHapticsController { get; }
  }
  public sealed class SimpleHapticsController
  public sealed class SimpleHapticsControllerFeedback
}
namespace Windows.UI.Input.Core {
  public sealed class RadialControllerIndependentInputSource
}
namespace Windows.UI.Input.Inking {
  public enum InkPersistenceFormat
  public sealed class InkPresenterProtractor : IInkPresenterStencil
  public sealed class InkPresenterRuler : IInkPresenterStencil {
    bool AreTickMarksVisible { get; set; }
    bool IsCompassVisible { get; set; }
  }
  public enum InkPresenterStencilKind {
    Protractor = 2,
  }
  public sealed class InkStroke {
    uint Id { get; }
    IReference<TimeSpan> StrokeDuration { get; set; }
    IReference<DateTime> StrokeStartedTime { get; set; }
  }
  public sealed class InkStrokeBuilder {
    InkStroke CreateStrokeFromInkPoints(IIterable<InkPoint> inkPoints, Matrix3x2 transform, IReference<DateTime> strokeStartedTime, IReference<TimeSpan> strokeDuration);
  }
  public sealed class InkStrokeContainer : IInkStrokeContainer {
    InkStroke GetStrokeById(uint id);
    IAsyncOperationWithProgress<uint, uint> SaveAsync(IOutputStream outputStream, InkPersistenceFormat inkPersistenceFormat);
  }
}
namespace Windows.UI.Input.Spatial {
  public sealed class SpatialHoldCompletedEventArgs {
    SpatialPointingPose TryGetPointingPose(SpatialCoordinateSystem coordinateSystem);
  }
  public sealed class SpatialHoldStartedEventArgs {
    SpatialPointingPose TryGetPointingPose(SpatialCoordinateSystem coordinateSystem);
  }
  public sealed class SpatialInteractionDetectedEventArgs {
    SpatialPointingPose TryGetPointingPose(SpatialCoordinateSystem coordinateSystem);
  }
  public enum SpatialInteractionKind
  public sealed class SpatialInteractionSource {
    bool SupportsPointing { get; }
  }
  public sealed class SpatialInteractionSourceEventArgs {
    SpatialInteractionKind InteractionKind { get; }
    SpatialPointingPose TryGetPointingPose(SpatialCoordinateSystem coordinateSystem);
  }
  public sealed class SpatialInteractionSourceState {
    bool IsGrasped { get; }
    bool IsPrimaryPressed { get; }
    bool IsSecondaryPressed { get; }
    SpatialPointingPose TryGetPointingPose(SpatialCoordinateSystem coordinateSystem);
  }
  public sealed class SpatialPointerPose {
    SpatialPointingPose TryGetPointingPose(SpatialInteractionSource source);
  }
  public sealed class SpatialPointingPose
  public sealed class SpatialTappedEventArgs {
    SpatialPointingPose TryGetPointingPose(SpatialCoordinateSystem coordinateSystem);
  }
}
namespace Windows.UI.Notifications {
  public sealed class NotificationData
  public enum NotificationUpdateResult
  public sealed class ToastCollection
  public sealed class ToastCollectionManager
  public sealed class ToastNotification {
    NotificationData Data { get; set; }
  }
  public sealed class ToastNotificationHistoryChangedTriggerDetail {
    string CollectionId { get; }
  }
  public static class ToastNotificationManager {
    public static ToastNotificationManagerForUser Current { get; }
  }
  public sealed class ToastNotificationManagerForUser {
    IAsyncOperation<ToastNotificationHistory> GetHistoryForToastCollectionIdAsync(string collectionId);
    ToastCollectionManager GetToastCollectionManager();
    ToastCollectionManager GetToastCollectionManager(string appId);
    IAsyncOperation<ToastNotifier> GetToastNotifierForToastCollectionIdAsync(string collectionId);
  }
  public sealed class ToastNotifier {
    NotificationUpdateResult Update(NotificationData data, string tag);
    NotificationUpdateResult Update(NotificationData data, string tag, string group);
  }
}
namespace Windows.UI.Text {
  public enum TextDecorations : uint
}
namespace Windows.UI.ViewManagement {
  public sealed class ApplicationView {
    IAsyncOperation<bool> TryConsolidateAsync();
  }
  public sealed class ApplicationViewConsolidatedEventArgs {
    bool IsAppInitiated { get; }
  }
}
namespace Windows.UI.WebUI {
  public sealed class WebUIContactPanelActivatedEventArgs : IActivatedEventArgs, IActivatedEventArgsDeferral, IActivatedEventArgsWithUser, IContactPanelActivatedEventArgs
  public sealed class WebUILockScreenComponentActivatedEventArgs : IActivatedEventArgs, IActivatedEventArgsDeferral
}
namespace Windows.UI.Xaml {
  public sealed class BringIntoViewOptions
  public class FrameworkElement : UIElement {
    public static void DeferTree(DependencyObject element);
  }
  public class UIElement : DependencyObject {
    double KeyTipHorizontalOffset { get; set; }
    public static DependencyProperty KeyTipHorizontalOffsetProperty { get; }
    KeyTipPlacementMode KeyTipPlacementMode { get; set; }
    public static DependencyProperty KeyTipPlacementModeProperty { get; }
    double KeyTipVerticalOffset { get; set; }
    public static DependencyProperty KeyTipVerticalOffsetProperty { get; }
    XYFocusKeyboardNavigationMode XYFocusKeyboardNavigation { get; set; }
    public static DependencyProperty XYFocusKeyboardNavigationProperty { get; }
    void StartBringIntoView();
    void StartBringIntoView(BringIntoViewOptions options);
  }
}
namespace Windows.UI.Xaml.Automation {
  public sealed class AutomationElementIdentifiers {
    public static AutomationProperty CultureProperty { get; }
  }
  public sealed class AutomationProperties {
    public static DependencyProperty CultureProperty { get; }
    public static int GetCulture(DependencyObject element);
    public static void SetCulture(DependencyObject element, int value);
  }
}
namespace Windows.UI.Xaml.Automation.Peers {
  public class AutomationPeer : DependencyObject {
    int GetCulture();
    virtual int GetCultureCore();
  }
  public sealed class MapControlAutomationPeer : FrameworkElementAutomationPeer, IScrollProvider, ITransformProvider, ITransformProvider2 {
    bool CanMove { get; }
    bool CanResize { get; }
    bool CanRotate { get; }
    bool CanZoom { get; }
    double MaxZoom { get; }
    double MinZoom { get; }
    double ZoomLevel { get; }
    void Move(double x, double y);
    void Resize(double width, double height);
    void Rotate(double degrees);
    void Zoom(double zoom);
    void ZoomByUnit(ZoomUnit zoomUnit);
  }
}
namespace Windows.UI.Xaml.Controls {
  public class ContentDialog : ContentControl {
    bool IsTertiaryButtonEnabled { get; set; }
    public static DependencyProperty IsTertiaryButtonEnabledProperty { get; }
    Style PrimaryButtonStyle { get; set; }
    public static DependencyProperty PrimaryButtonStyleProperty { get; }
    Style SecondaryButtonStyle { get; set; }
    public static DependencyProperty SecondaryButtonStyleProperty { get; }
    ICommand TertiaryButtonCommand { get; set; }
    object TertiaryButtonCommandParameter { get; set; }
    public static DependencyProperty TertiaryButtonCommandParameterProperty { get; }
    public static DependencyProperty TertiaryButtonCommandProperty { get; }
    Style TertiaryButtonStyle { get; set; }
    public static DependencyProperty TertiaryButtonStyleProperty { get; }
    string TertiaryButtonText { get; set; }
    public static DependencyProperty TertiaryButtonTextProperty { get; }
    event TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> TertiaryButtonClick;
  }
  public enum ContentDialogResult {
    Tertiary = 3,
  }
  public class Control : FrameworkElement {
    Uri DefaultStyleResourceUri { get; set; }
    public static DependencyProperty DefaultStyleResourceUriProperty { get; }
  }
  public sealed class FocusEngagedEventArgs : RoutedEventArgs {
    bool Handled { get; set; }
  }
  public class Frame : ContentControl, INavigate {
    void SetNavigationState(string navigationState, bool suppressNavigate);
  }
  public class InkToolbar : Control {
    InkToolbarButtonFlyoutPlacement ButtonFlyoutPlacement { get; set; }
    public static DependencyProperty ButtonFlyoutPlacementProperty { get; }
    bool IsStencilButtonChecked { get; set; }
    public static DependencyProperty IsStencilButtonCheckedProperty { get; }
    Orientation Orientation { get; set; }
    public static DependencyProperty OrientationProperty { get; }
    event TypedEventHandler<InkToolbar, object> BringStencilIntoViewRequested;
    event TypedEventHandler<InkToolbar, object> EraserWidthChanged;
    event TypedEventHandler<InkToolbar, InkToolbarIsStencilButtonCheckedChangedEventArgs> IsStencilButtonCheckedChanged;
    InkToolbarMenuButton GetMenuButton(InkToolbarMenuKind menu);
  }
  public enum InkToolbarButtonFlyoutPlacement
  public class InkToolbarEraserButton : InkToolbarToolButton {
    InkToolbarEraserKind EraserKind { get; set; }
    public static DependencyProperty EraserKindProperty { get; }
    bool IsClearAllVisible { get; set; }
    public static DependencyProperty IsClearAllVisibleProperty { get; }
    bool IsWidthSliderVisible { get; set; }
    public static DependencyProperty IsWidthSliderVisibleProperty { get; }
    double MaxStrokeWidth { get; set; }
    public static DependencyProperty MaxStrokeWidthProperty { get; }
    double MinStrokeWidth { get; set; }
    public static DependencyProperty MinStrokeWidthProperty { get; }
    double SelectedStrokeWidth { get; set; }
    public static DependencyProperty SelectedStrokeWidthProperty { get; }
  }
  public enum InkToolbarEraserKind
  public class InkToolbarFlyoutItem : ButtonBase
  public enum InkToolbarFlyoutItemKind
  public sealed class InkToolbarIsStencilButtonCheckedChangedEventArgs
  public class InkToolbarMenuButton : ToggleButton
  public enum InkToolbarMenuKind
  public class InkToolbarPenConfigurationControl : Control {
    InkToolbarEraserButton EraserButton { get; }
    public static DependencyProperty EraserButtonProperty { get; }
  }
  public class InkToolbarStencilButton : InkToolbarMenuButton
  public enum InkToolbarStencilKind
  public sealed class RichTextBlock : FrameworkElement {
    TextDecorations TextDecorations { get; set; }
    public static DependencyProperty TextDecorationsProperty { get; }
  }
  public sealed class TextBlock : FrameworkElement {
    TextDecorations TextDecorations { get; set; }
    public static DependencyProperty TextDecorationsProperty { get; }
  }
}
namespace Windows.UI.Xaml.Controls.Maps {
  public sealed class MapBillboard : MapElement
  public sealed class MapContextRequestedEventArgs
  public sealed class MapControl : Control {
    MapProjection MapProjection { get; set; }
    public static DependencyProperty MapProjectionProperty { get; }
    MapStyleSheet StyleSheet { get; set; }
    public static DependencyProperty StyleSheetProperty { get; }
    Thickness ViewPadding { get; set; }
    public static DependencyProperty ViewPaddingProperty { get; }
    event TypedEventHandler<MapControl, MapContextRequestedEventArgs> MapContextRequested;
    IVectorView<MapElement> FindMapElementsAtOffset(Point offset, double radius);
    void GetLocationFromOffset(Point offset, AltitudeReferenceSystem desiredReferenceSystem, out Geopoint location);
    void StartContinuousPan(double horizontalPixelsPerSecond, double verticalPixelsPerSecond);
    void StopContinuousPan();
    IAsyncOperation<bool> TryPanAsync(double horizontalPixels, double verticalPixels);
    IAsyncOperation<bool> TryPanToAsync(Geopoint location);
  }
  public enum MapProjection
  public enum MapStyle {
    Custom = 7,
  }
  public sealed class MapStyleSheet : DependencyObject
}
namespace Windows.UI.Xaml.Controls.Primitives {
  public class FlyoutBase : DependencyObject {
    DependencyObject OverlayInputPassThroughElement { get; set; }
    public static DependencyProperty OverlayInputPassThroughElementProperty { get; }
  }
}
namespace Windows.UI.Xaml.Documents {
  public sealed class Hyperlink : Span {
    FocusState FocusState { get; }
    public static DependencyProperty FocusStateProperty { get; }
    event RoutedEventHandler GotFocus;
    event RoutedEventHandler LostFocus;
    bool Focus(FocusState value);
  }
  public class TextElement : DependencyObject {
    double KeyTipHorizontalOffset { get; set; }
    public static DependencyProperty KeyTipHorizontalOffsetProperty { get; }
    KeyTipPlacementMode KeyTipPlacementMode { get; set; }
    public static DependencyProperty KeyTipPlacementModeProperty { get; }
    double KeyTipVerticalOffset { get; set; }
    public static DependencyProperty KeyTipVerticalOffsetProperty { get; }
    TextDecorations TextDecorations { get; set; }
    public static DependencyProperty TextDecorationsProperty { get; }
    event TypedEventHandler<TextElement, AccessKeyDisplayDismissedEventArgs> AccessKeyDisplayDismissed;
    event TypedEventHandler<TextElement, AccessKeyDisplayRequestedEventArgs> AccessKeyDisplayRequested;
    event TypedEventHandler<TextElement, AccessKeyInvokedEventArgs> AccessKeyInvoked;
  }
}
namespace Windows.UI.Xaml.Input {
  public sealed class AccessKeyManager {
    public static bool AreKeyTipsEnabled { get; set; }
  }
  public enum KeyTipPlacementMode
  public enum XYFocusKeyboardNavigationMode
}
namespace Windows.UI.Xaml.Markup {
  public sealed class XamlMarkupHelper
}
 
namespace Windows.Media.Capture {
  public sealed class AppCaptureDurationGeneratedEventArgs
  public sealed class AppCaptureFileGeneratedEventArgs
  public enum AppCaptureMicrophoneCaptureState
  public sealed class AppCaptureMicrophoneCaptureStateChangedEventArgs
  public enum AppCaptureRecordingState
  public sealed class AppCaptureRecordingStateChangedEventArgs
  public sealed class AppCaptureRecordOperation
  public sealed class AppCaptureServices
  public sealed class AppCaptureState
}
 
namespace Windows.Services.Store {
  public sealed class StoreContext {
    IAsyncOperation<StoreProductResult> FindStoreProductForPackageAsync(IIterable<string> productKinds, Package package);
  }
}

API Removals

namespace Windows.UI.Composition {
  public sealed class CompositionDrawingSurface : CompositionObject, ICompositionSurface {
  }
}

API Additions not yet implemented

The Bluetooth APIs were included to receive feedback from the Developer community.

namespace Windows.Devices.Bluetooth {
  public sealed class BluetoothAdapter
  public sealed class BluetoothDeviceId
  public enum BluetoothError {
    TransportNotSupported = 9,
  }
  public sealed class BluetoothLEDevice : IClosable {
    DeviceAccessInformation DeviceAccessInformation { get; }
    IAsyncOperation<GattDeviceServicesResult> GetGattServicesAsync();
    IAsyncOperation<GattDeviceServicesResult> GetGattServicesAsync(BluetoothCacheMode cacheMode);
    IAsyncOperation<GattDeviceServicesResult> GetGattServicesForUuidAsync(GattUuid serviceUuid);
    IAsyncOperation<GattDeviceServicesResult> GetGattServicesForUuidAsync(GattUuid serviceUuid, BluetoothCacheMode cacheMode);
    IAsyncOperation<DeviceAccessStatus> RequestAccessAsync();
  }
  public enum BluetoothTransportOptions : uint
}
namespace Windows.Devices.Bluetooth.Background {
  public enum BluetoothEventTriggeringMode
  public sealed class GattCharacteristicNotificationTriggerDetails {
    BluetoothError Error { get; }
    BluetoothEventTriggeringMode EventTriggeringMode { get; }
    IVectorView<GattValueChangedEventArgs> ValueChangedEvents { get; }
  }
  public sealed class GattServiceProviderBackgroundInfo
  public sealed class GattServiceProviderRequestActivityInfo
  public enum GattServiceProviderRequestActivityType
  public enum GattServiceProviderRequestAttributeType
  public sealed class GattServiceProviderTriggerDetails
  public enum GattServiceProviderTriggerReason
}
namespace Windows.Devices.Bluetooth.GenericAttributeProfile {
  public sealed class GattCharacteristic {
    IAsyncOperation<GattDescriptorsResult> GetDescriptorsAsync();
    IAsyncOperation<GattDescriptorsResult> GetDescriptorsAsync(BluetoothCacheMode cacheMode);
    IAsyncOperation<GattDescriptorsResult> GetDescriptorsForUuidAsync(GattUuid descriptorUuid);
    IAsyncOperation<GattDescriptorsResult> GetDescriptorsForUuidAsync(GattUuid descriptorUuid, BluetoothCacheMode cacheMode);
    IAsyncOperation<GattWriteResult> WriteValueWithResultAsync(IBuffer value);
    IAsyncOperation<GattWriteResult> WriteValueWithResultAsync(IBuffer value, GattWriteOption writeOption);
  }
  public sealed class GattCharacteristicsResult
  public sealed class GattClientNotificationResult
  public enum GattCommunicationStatus {
    ProtocolError = 2,
  }
  public sealed class GattDescriptor {
    IAsyncOperation<GattWriteResult> WriteValueWithResultAsync(IBuffer value);
  }
  public sealed class GattDescriptorsResult
  public sealed class GattDeviceService : IClosable {
    DeviceAccessInformation DeviceAccessInformation { get; }
    GattSession Session { get; }
    public static IAsyncOperation<GattDeviceService> FromIdAsync(string deviceId, GattSharingMode sharingMode);
    IAsyncOperation<GattCharacteristicsResult> GetCharacteristicsAsync();
    IAsyncOperation<GattCharacteristicsResult> GetCharacteristicsAsync(BluetoothCacheMode cacheMode);
    IAsyncOperation<GattCharacteristicsResult> GetCharacteristicsForUuidAsync(GattUuid characteristicUuid);
    IAsyncOperation<GattCharacteristicsResult> GetCharacteristicsForUuidAsync(GattUuid characteristicUuid, BluetoothCacheMode cacheMode);
    public static string GetDeviceSelector(GattUuid gattUuid);
    public static string GetDeviceSelectorForBluetoothDeviceId(BluetoothDeviceId bluetoothDeviceId);
    public static string GetDeviceSelectorForBluetoothDeviceId(BluetoothDeviceId bluetoothDeviceId, BluetoothCacheMode cacheMode);
    public static string GetDeviceSelectorForBluetoothDeviceIdAndGattUuid(BluetoothDeviceId bluetoothDeviceId, GattUuid gattUuid);
    public static string GetDeviceSelectorForBluetoothDeviceIdAndGattUuid(BluetoothDeviceId bluetoothDeviceId, GattUuid gattUuid, BluetoothCacheMode cacheMode);
    IAsyncOperation<GattDeviceServicesResult> GetIncludedServicesAsync();
    IAsyncOperation<GattDeviceServicesResult> GetIncludedServicesAsync(BluetoothCacheMode cacheMode);
    IAsyncOperation<GattDeviceServicesResult> GetIncludedServicesForUuidAsync(GattUuid serviceUuid);
    IAsyncOperation<GattDeviceServicesResult> GetIncludedServicesForUuidAsync(GattUuid serviceUuid, BluetoothCacheMode cacheMode);
    IAsyncOperation<DeviceAccessStatus> RequestAccessAsync(GattSharingMode sharingMode);
  }
  public sealed class GattDeviceServicesResult
  public sealed class GattLocalCharacteristic
  public sealed class GattLocalCharacteristicParameters
  public sealed class GattLocalDescriptor
  public sealed class GattLocalDescriptorParameters
  public sealed class GattPresentationFormat {
    public static GattPresentationFormat FromParts(byte formatType, int exponent, ushort unit, byte namespaceId, ushort description);
  }
  public static class GattProtocolError
  public sealed class GattPublishedService
  public sealed class GattReadClientCharacteristicConfigurationDescriptorResult {
    IReference<byte> ProtocolError { get; }
  }
  public sealed class GattReadRequest
  public sealed class GattReadRequestedEventArgs
  public sealed class GattReadResponse
  public sealed class GattReadResult {
    IReference<byte> ProtocolError { get; }
  }
  public sealed class GattReliableWriteTransaction {
    IAsyncOperation<GattWriteResult> CommitWithResultAsync();
  }
  public sealed class GattServiceProvider
  public sealed class GattServiceProviderAdvertisingParameters
  public sealed class GattServiceProviderResult
  public enum GattServiceProviderStatus
  public sealed class GattServiceProviderStatusChangedEventArgs
  public enum GattServiceType
  public sealed class GattSession : IClosable
  public enum GattSessionStatus
  public sealed class GattSessionStatusChangedEventArgs
  public enum GattSharingMode
  public sealed class GattSubscribedClient
  public sealed class GattUuid
  public sealed class GattWriteRequest
  public sealed class GattWriteRequestedEventArgs
  public sealed class GattWriteResponse
  public sealed class GattWriteResult
}
namespace Windows.Devices.Bluetooth.Rfcomm {
  public sealed class RfcommDeviceService : IClosable {
    public static IAsyncOperation<RfcommDeviceServicesResult> FromIdWithResultAsync(string deviceId);
  }
  public sealed class RfcommServiceProvider {
    public static IAsyncOperation<RfcommServiceProviderResult> CreateWithResultAsync(RfcommServiceId serviceId);
  }
  public sealed class RfcommServiceProviderResult
}
 

Kinect demo code and new driver for UWP now available

Here’s a little memory test: Do you recall this blog, which posted back in May and promised to soon begin integrating Kinect for Windows into the Universal Windows Platform? Of course you do! Now we are pleased to announce two important developments in the quest to make Kinect functionality available to UWP apps.

First, by popular demand, the code that Alex Turner used during his Channel 9 video (above) is now available on GitHub as part of the Windows universal samples. With this sample, you can use Windows.Media.Capture.Frames APIs to enumerate the Kinect sensor’s RGB/IR/depth cameras and then use MediaFrameReader to stream frames. This API lets you access pixels of each individual frame directly in a highly efficient way.

These new functionalities debuted in the Windows 10 Anniversary Update, and structure of the APIs should be familiar to those who’ve been using the Kinect SDK for years. But these new APIs are designed to work not only with the Kinect sensor but with any other sensors capable of delivering rich data streams—provided you have a matching device driver.

Which brings us to our second announcement: We have now enabled the Kinect driver on Windows Update. So if you’d like try out this new functionality now, simply go to the Device Manager and update the driver for the Kinect sensor. In addition to enabling the new UWP APIs described above, the new driver also lets you use the Kinect color camera as a normal webcam. This means that apps which use a webcam, such as Skype, can now employ the Kinect sensor as their source. It also means that you can use the Kinect sensor to enable Windows Hello for authentication via facial recognition.

picture1

Another GitHub sample demonstrates how to use new special-correlation APIs, such as CameraIntrinsics or DepthCorrelatedCoordinateMapper, to process RGB and depth camera frames for background removal. These APIs take advantage of the fact that the Kinect sensor’s color and depth cameras are spatially correlated by calibration and depth frame data. This sample also shows how to access the Kinect sensor’s skeletal tracking data through a custom media stream in UWP apps with newly introduced APIs.

Finally, we should note that the Xbox summary update also enables these Kinect features through Windows.Media.Capture.Frames for UWP apps. Thus, apps that use the Kinect sensor’s RGB, infrared, and/or depth cameras will run on Xbox with same code, and Xbox can also use the Kinect RGB camera as a normal webcam for Skype-like scenarios

Judging from requests, we’re confident that many of you are eager to explore both the demo code and download the new driver. When you do, we want to hear about your experiences—what you liked, what you didn’t, and what enhancements you want to see. So send us your feedback!

Please note that, if you have technical questions about this post or would like to discuss Kinect with other developers and Microsoft engineers, we hope you will join the conversation on the Kinect for Windows v2 SDK forum. You can browse existing topics or ask a new question by clicking the Ask a question button on the forum webpage.

The Kinect for Windows Team

Key links

Getting personal – speech and inking (App Dev on Xbox series)

The way users interact with apps on different devices has gotten much more personal lately, thanks to a variety of new Natural User Interface features in the Universal Windows Platform. These UWP patterns and APIs are available for developers to easily bring in capabilities for their apps that enable more human technologies. For the final blog post in the series, we have extended the Adventure Works sample to add support for Ink on devices that support it, and to add support for speech interaction where it makes sense (including both synthesis and recognition). Make sure to get the updated code for the Adventure Works Sample from the GitHub repository so you can refer to it as you read on.

And in case you missed the blog post from last week on how to enable great social experiences, we covered how to connect your app to social networks such as Facebook and Twitter, how to enable second screen experiences through Project “Rome”, and how to take advantage of the UWP Maps control and make your app location aware. To read last week’s blog post or any of the other blog posts in the series, or to watch the recordings from the App Dev on Xbox live event that started it all, visit the App Dev on Xbox landing page.

Adventure Works (v3)

picture1

We are continuing to build on top of the Adventure Works sample app we worked with in the previous two blog posts. If you missed those, make sure to check them out here and here. As a reminder, Adventure Works is a social photo app that allows the user to:

  • Capture, edit, and store photos for a specific trip
  • auto analyze and auto tag friends using Cognitive Services vision APIs
  • view albums from friends on an interactive map
  • share albums on social networks like Facebook and Twitter
  • Use one device to remote control slideshows running on another device using project Rome
  • and more …

There is always more to be done, and for this final round of improvements we will focus on two sets of features:

  1. Ink support to annotate images, enable natural text input, as well as the ability to use inking as a presentation tool in connected slideshow mode.
  2. Speech Synthesis and Speech Recognition (with a little help from cognitive services for language understanding) to create a way to quickly access information using speech.

More Personal Computing with Ink

Inking in Windows 10 allows users with Inking capable devices to draw and annotate directly on the screen with a device like the Surface Pen – and if you don’t have a pen handy, you can use your finger or a mouse instead. Windows 10 built-in apps like Sticky Notes, Sketchpad and Screen sketch support inking, as do many Office products. Besides preserving drawings and annotations, inking also uses machine learning to recognize and convert ink to text. OneNote goes a step further by recognizing shapes and equations in addition to text.

picture2

Best of all, you can easily add Inking functionality into your own apps, as we did for Adventure Works,  with one line of XAML markup to create an InkCanvas. With just one more line, you can add an InkToolbar to your canvas that provides a color selector as well as buttons for drawing, erasing, highlighting, and displaying a ruler. (In case you have the Adventure Works project open, the InkCanvas and InkToolbar implementation can be found in PhotoPreviewView.)


<InkCanvas x:Name=”Inker”></InkCanvas>
<InkToolbar TargetInkCanvas=”{x:Bind Inker}” VerticalAlignment=”Top”/>

The InkCanvas allows users to annotate their Adventure Works slideshow photos. This can be done both directly as well as remotely through the Project “Rome” code highlighted in the previous post. When done on the same device, the ink strokes are saved off to a GIF file which is then associated with the original slideshow image.

picture3

When the image is displayed again during later viewings, the strokes are extracted from the GIF file, as shown in the code below, and inserted back into a canvas layered on top of the image in PhotoPreviewView. The code for saving and extracting ink strokes are found in the InkHelpers class.


var file = await StorageFile.GetFileFromPathAsync(filename);
if (file != null)
{
    using (var stream = await file.OpenReadAsync())
    {
        inker.InkPresenter.StrokeContainer.Clear();
        await inker.InkPresenter.StrokeContainer.LoadAsync(stream);
    }
}

Ink strokes can also be drawn on one device (like a Surface device) and displayed on another one (an Xbox One). In order to do this, the Adventure Works code actually collects the user’s pen strokes using the underlying InkPresenter object that powers the InkCanvas. It then converts the strokes into a byte array and serializes them over to the remote instance of the app. You can find out more about how this is implemented in Adventure Works by looking through the GetStrokeData method in SlideshowSlideView control and the SendStrokeUpdates method in SlideshowClientPage.

It is sometimes useful to save the ink strokes and original image in a new file. In Adventure Works, this is done to create a thumbnail version of an annotated slide for quick display as well as for uploading to Facebook. You can find the code used to combine an image file with an ink stroke annotation in the RenderImageWithInkToFIleAsync method in the InkHelpers class. It uses the Win2D DrawImage and DrawInk methods of a CanvasDrawingSession object to blend the two together, as shown in the snippet below.


CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)inker.ActualWidth, (int)inker.ActualHeight, 96);

var image = await CanvasBitmap.LoadAsync(device, imageStream);
using (var ds = renderTarget.CreateDrawingSession())
{
    var imageBounds = image.GetBounds(device);
                
    //...

    ds.Clear(Colors.White);
    ds.DrawImage(image, new Rect(0, 0, inker.ActualWidth, inker.ActualWidth), imageBounds);
    ds.DrawInk(inker.InkPresenter.StrokeContainer.GetStrokes());
}

Ink Text Recognition

picture4

Adventure Works also takes advantage of Inking’s text recognition feature to let users handwrite the name of their newly created Adventures. This capability is extremely useful if someone is running your app in tablet mode with a pen and doesn’t want to bother with the onscreen keyboard. Converting ink to text relies on the InkRecognizer class. Adventure Works encapsulates this functionality in a templated control called InkOverlay which you can reuse in your own code. The core implementation of ink to text really just requires instantiating an InkRecognizerContainer and then calling its RecognizeAsync method.


var inkRecognizer = new InkRecognizerContainer();
var recognitionResults = await inkRecognizer.RecognizeAsync(_inker.InkPresenter.StrokeContainer, InkRecognitionTarget.All);

You can imagine this being very powerful when the user has a large form to fill out on a tablet device and they don’t have to use the onscreen keyboard.

More Personal Computing with Speech

There are two sets of APIs that are used in Adventure Works that enable a great natural experience using speech. First, UWP speech APIs allow developers to integrate speech-to-text (recognition) and text-to-speech (synthesis) into their UWP apps. Speech recognition converts words spoken by the user into text for form input, for text dictation, to specify an action or command, and to accomplish tasks. Both free-text dictation and custom grammars authored using Speech Recognition Grammar Specification are supported.

Second, Language Understanding Intelligent Service (LUIS) is a Microsoft Cognitive Services API that uses machine learning to help your app figure out what people are trying to say. For instance, if someone wants to order food, they might say “find me a restaurant” or “I’m hungry” or “feed me”. You might try a brute force approach to recognize the intent to order food, listing out all the variations on the concept “order food” that you can think of – but of course you’re going to come up short. LUIS lets you set up a model for the “order food” intent that learns, over time, what people are trying to say.

In Adventure Works, these features are combined to create a variety of speech related functionalities. For instance, the app can listen for an utterance like “Adventure Works, start my latest slideshow” and it will naturally open a slideshow for you when it hears this command. It can also respond using speech when appropriate to answer a question. LUIS, in turn, augments this speech recognition with language understanding to improve the recognition of natural language phrases.

picture5

The speech capabilities for our app are wrapped in a simple assistant called Adventure Works Aide (look for AdventureWorksAideView.xaml). Saying the phrase “Adventure Works…” will invoke it. It will then listen for spoken patterns such as:

  • “What adventures are in <location>.”
  • “Show me <person> adventure.”
  • “Who is closes to me.”

Adventure Works Aide is powered by a custom SpeechService class. There are two SpeechRecognizer instances that are used at different times, first to recognize the “Adventure Works” phrase at any time:


_continousSpeechRecognizer = new SpeechRecognizer();
_continousSpeechRecognizer.Constraints.Add(new SpeechRecognitionListConstraint(new List&amp;lt;String&amp;gt;() { &amp;quot;Adventure Works&amp;quot; }, &amp;quot;start&amp;quot;));
var result = await _continousSpeechRecognizer.CompileConstraintsAsync();
//...
await _continousSpeechRecognizer.ContinuousRecognitionSession.StartAsync(SpeechContinuousRecognitionMode.Default);
and then to understand free form natural language and convert it to text:
_speechRecognizer = new SpeechRecognizer();
var result = await _speechRecognizer.CompileConstraintsAsync();
SpeechRecognitionResult speechRecognitionResult = await _speechRecognizer.RecognizeAsync();
if (speechRecognitionResult.Status == SpeechRecognitionResultStatus.Success)
{
    string str = speechRecognitionResult.Text;
}

As you can see, the SpeechRecognizer API is used for both listening continuously for specific constraints throughout the lifetime of the app, or to convert any free-form speech to text at a specific time. The continuous recognition session can be set to recognize phrases from a list of strings, or it can even use a more structured SRGS grammar file which provides the greatest control over the speech recognition by allowing for multiple semantic meanings to be recognized at once. However, because we want to understand every variation the user might say and use LUIS for our semantic understanding, we can use the free-form speech recognition with the default constraints.

Note: before using any of the speech APIs on Xbox, the user must give permission to your application to access the microphone. Not all APIs automatically show the dialog currently so you will need to invoke the dialog yourself. Checkout the CheckForMicrophonePermission function in SpeechService.cs to see how this is done in Adventure Works.

When the continuous speech recognizer recognizes the key phrase, it immediately stops listening, shows the UI for the AdventureWorksAide to let the user know that it’s listening, and starts listening for natural language.


await _continousSpeechRecognizer.ContinuousRecognitionSession.CancelAsync();
ShowUI();
SpeakAsync(&amp;quot;hey!&amp;quot;);
var spokenText = await ListenForText();

Subsequent utterances are passed on to LUIS which uses training data we have provided to create a machine learning model to identify specific intents. For this app, we have three different intents that can be recognized: showuser, showmap, and whoisclosest (but you can always add more). We have also defined an entity for username for LUIS to provide us with the name of the user when the showuser intent has been recognized. LUIS also provides several pre-built entities that have been trained for specific types of data; in this case, we are using an entity for geography locations in the showmap intent.

picture6

To use LUIS in the app, we used the official nugget library which allowed us to register specific handlers for each intent when we send over a phrase.


var handlers = new LUISIntentHandlers();
_router = IntentRouter.Setup(Keys.LUISAppId, Keys.LUISAzureSubscriptionKey, handlers, false);
var handled = await _router.Route(text, null);

Take a look at the HandleIntent method in the LUISAPI.cs file and the LUISIntentHandlers class which handles each intent defined in the LUIS portal, and is a useful reference for future LUIS implementations.

Finally, once the text has been processed by LUIS and the intent has been processed by the app, the AdventureWorksAide might need to respond back to the user using speech, and for that, the SpeechService uses the SpeechSynthesizer API:


_speechSynthesizer = new SpeechSynthesizer();
var syntStream = await _speechSynthesizer.SynthesizeTextToStreamAsync(toSpeak);
_player = new MediaPlayer();
_player.Source = MediaSource.CreateFromStream(syntStream, syntStream.ContentType);
_player.Play();

The SpeechSynthesizer API can specify a specific voice to use for the generation based on voices installed on the system, and it can even use SSML (speech synthesis markup language) to control how the speech is generated, including volume, pronunciation, and pitch.

The entire flow, from invoking the Adventure Works Aide to sending the spoken text to LUIS, and finally responding to the user is handled in the WakeUpAndListen method.

There’s more

Though not used in the current version of the project, there are other APIs that you can take advantage of for your apps, both as part of the UWP platform and as part of Cognitive Services.

For example, on desktop and mobile device, Cortana can recognize speech or text directly from the Cortana canvas and activate your app or initiate an action on behalf of your app. It can also expose actions to the user based on insights about them, and with user permission it can even complete the action for them. Using a Voice Command Definition (VCD) file, developers have the option to add commands directly to the Cortana command set (commands like: “Hey Cortana show adventure in Europe in Adventure Works”). Cortana app integration is also part of our long-term plans for voice support on Xbox, even though it is not supported today. Visit the Cortana portal for more info.

In addition, there are several speech and language related Cognitive Services APIs that are simply too cool not to mention:

  • Custom Recognition Service – Overcomes speech recognition barriers like speaking style, background noise, and vocabulary.
  • Speaker Recognition – Identify individual speakers or use speech as a means of authentication with the Speaker Recognition API.
  • Linguistic Analysis – Simplify complex language concepts and parse text with the Linguistic Analysis API.
  • Translator – Translate speech and text with a simple REST API call.
  • Bing Spell Check – Detect and correct spelling mistakes within your app.

The more personal computing features provided through Cognitive Services is constantly being refreshed, so be sure to check back often to see what new machine learning capabilities have been made available to you.

That’s all folks

This was the last blog post (and sample app) in the App Dev on Xbox series, but if you have a great idea that we should cover, please just let us know, we are always looking for cool app ideas to build and features to implement. Make sure to check out the app source on our official GitHub repository, read through some of the resources provided, read through some of the other blog posts or watch the event if you missed it, and let us know what you think through the comments below or on twitter.

Happy coding!

Resources

Previous Xbox Series Posts

New Windows Store submission API capabilities

The Windows Store submission API was launched earlier this year, enabling you to automate app, IAP durables and consumables, and package flights publishing through a REST API. Using the submission API helps speed up publishing, automate release management and reduce publishing errors.

This month, the submission API added two new capabilities:

If you try the submission API and receive an access denied error, please use the Feedback option at the bottom right of the Dev Center dashboard and select Submission API for the feedback area to request access.

To get started, read the API documentation and samples. You can also use Windows Store analytics API, which retrieves analytics data for all the apps in your account also through a REST API.

Download Visual Studio to get started.

The Windows team would love to hear your feedback.  Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.

UWP Hosted Web App on Xbox One (App Dev on Xbox series)

For the fourth installment in the series, we are open sourcing yet another sample app: South Ridge Video, an open source video app developed as a hosted web application built with React.js and hosted on a web server. South Ridge can easily be converted to a UWP application that takes advantage of native platform capabilities and can be distributed through the Windows Store as any other UWP app. The source code is available on GitHub right now, so make sure to check it out.

If you missed the previous blog post from last week on Background Audio and Cross Platform Development with Xamarin, make sure to check it out. We covered how to build a cross-device music experience using Xamarin and how to support background audio on the Universal Windows Platform, including the Xbox One. To read the other blog posts and watch the recordings from the App Dev on Xbox live event that started it all, visit the App Dev on Xbox landing page.

South Ridge Video

image1

What if you could extend the investment put into your web application and make it available as an Xbox One Windows Store app? What if you could also continue to use your existing web frameworks, CDN and server backend, yet still be able to use native Windows 10 APIs?

You can! A Hosted Web App (HWA) is a web app that can be submitted to the Store just like any other Universal Windows Platform (UWP) app. Since you’ve already invested in the development of the web app, your transformation into a HWA can be done rather quickly and easily.

To do this, you’ll reuse your existing code and frameworks as if you were developing for the browser. Let’s take a look at the South Ridge Video example app on GitHub. This is an app built with React.js and uses a web server back-end.  The application is delivered by the server when the app is launched and the UWP app will host that web content.

However, the HWA is not just a simple wrapper; you can also call into native Windows 10 APIs, such as adding an event to the user’s calendar. You can even use APIs such as toast notifications and camera capture or media transport controls with background audio. Note that when accessing sensitive APIs, make sure you declare the required App Capability in the appmanifest.

Now that your web app is ready and you want to turn it into a HWA, let’s take a look at the things you need to do to get it ready for Windows Store distribution to Xbox One.

Local Testing on a retail Xbox One

First, you need to put your retail Xbox One into developer mode so you can deploy and test the app. This is pretty straightforward; it involves installing an app from the Windows Store. Go here to see the steps on how to activate dev mode and how it works.

Now that you have your Xbox ready for deployment, let’s review the ways you can generate the app. There are three main options:

  • Using a web browser-based tool, such as Windows App Studio, to generate it for you
  • On a Mac or PC using Manifold.js
  • On a PC using Visual Studio

Let’s drill down into each option to see which best fits your needs.

Windows App Studio

Let’s start with the browser-based option, using Windows App Studio to create the HWA. Windows App Studio is a free online app creation tool that allows you to quickly build Windows 10 apps.

  1. Open Windows App Studio in your web browser.
  2. Click Start now!
  3. Under Web app templates, click Hosted Web App.
  4. Follow the on-screen instructions to generate a package ready for publishing to the Windows Store.
  5. You can then download the generate package that you’ll publish to the Store.

On a Mac using Manifold.js

What you need:

  • A web browser
  • A command prompt

ManifoldJS is a Node.js app that easily installs from NPM. It takes the meta-data about your web site and generates native hosted apps across Android, iOS and Windows. If your site does not have a web app manifest, one will be automatically generated for you. For example, take a look at the web app manifest for South Ridge Video.

  1. Install NodeJS, which includes NPM (Node Package Manager)
  2. Open a command prompt and type “NPM install -g manifoldJS”
    1. npm install -g manifoldjs
  3. Run themanifoldjs command on your web site URL:
    1. manifoldjs http://southridge.azurewebsites.net
  4. Follow the steps in the video below to complete the packaging (and publish your Hosted Web App to the Windows Store)

image2

A couple notes about using Manifold.js

  • If you have a W3C manifest, it will use that for app info; otherwise, it will be created automatically.
  • Use the -windows10 platform flag to generate only for UWP.

On a Windows PC using Visual Studio

What you need:

  • Visual Studio 2015. The free, full-featured Visual Studio Community 2015 includes Windows 10 developer tools, universal app templates, a code editor, a powerful debugger, Windows Mobile emulators, rich language support and much more—all ready to use in production. The same is true for Professional or Enterprise variants of VS 2015.
  • (Optional) Windows Standalone SDK for Windows 10. If you are using a development environment other than Visual Studio 2015, you can download a standalone Windows SDK for Windows 10 installer. Note that you do not need to install this SDK if you’re using Visual Studio 2015 Update 3; it is already included.

Steps to create the HWA (go here to see all these steps with screenshots):

  • Pick the website URL and copy it into your clipboard.
  • Launch Visual Studio 2015.
    1. Click File.
    2. Click New Project.
    3. Under JavaScriptthen Windows Universal, click Blank App (Windows Universal).
  • Delete the VS project template generated code.
    1. Since this is a hosted web app where the content is served from a remote server, you will not need most of the local app files that come with the JavaScript template by default. Delete any local HTML, JavaScript, or CSS resources. All that should remain is theappxmanifest file, where you configure the app and the image resources.
  • Open the appxmanifestfile.
    1. Under the Application tab, find the Start page text field.
    2. Replace html with your website URL.
  • Set the boundaries of your app.
    1. Application Content URI Rules (ACURs) specify which remote URLs are allowed access to your app and to the Universal Windows APIs. At the very minimum, you will need to add an ACUR for your start page and any web resources utilized by that page. For more information on ACURs, click here.
    2. Open theappxmanifest file.
    3. Click theContent URIs.
    4. Add any necessary URIs for your start page.

For example:

  1. 1. http://southridge.azurewebsites.net2. http://*.azurewebsites.net
  2. Set theWinRT Access to All (for each URI you added).
  • At this point, you have a fully functioning Windows 10 app capable of accessing Universal Windows APIs! You can now deploy to the Xbox One using the remote debugger as if it were any Windows 10 remote device, or you can use the Device Portal (covered in the next section).

Installing your HWA on the Xbox One for local testing

At this point, you now have an app package (APPX) or a manifest folder (Manifold.js), containing the files you need to install or publish your application. You can “side-load” your HWA to the Xbox by using the Device Portal (go here for more information about the Device Portal for Xbox One). One you’ve logged into the portal, you can then deploy your app.

APPX Deployment (Visual Studio / App Studio)

Here are the steps (go here to see these steps below with screenshots):

  1. Go to the Apps tab on the portal.
  2. You’ll see two buttons to upload items to the device: App Package and Dependencies.
  3. Tap the App Package button and navigate to the package folder you generated for your app. In there, you’ll find an appx file. Select that file and upload it.
  4. Now tap the Dependencies button, navigate again to your package folder and drill down to the dependencies sub folder. This contains the dependencies that your app needs to run – upload each one in the folder. (Note that you only need to do this when deploying via the Portal. Visual Studio delivers dependencies when remote debugging and the end user’s machine will already have these installed when delivered via the Store.)
  5. With the app package and the dependencies uploaded, click the Go button under the “Deploy” section and the app will be installed.
  6. Now go to the Xbox and launch the app!

Loose Files Deployment (Manifold.js)

The only difference between deploying an app packages with Manifold.js is that you have “loose” files instead of an APPX package. In the steps above, instead of uploading an APPX and Dependencies, you choose the “upload loose files” option and select the manifest folder. The portal will look in that folder for the manifest file and gather all the required pieces to complete the installation.

Design and User Experience Considerations for Xbox One apps

Designing for the “10-Foot Experience”

Xbox One is considered a “10-foot experience”, meaning that your users will likely be sitting a minimum of 10 feet away from the screen. You’ll want to consider the app’s ability to be used at that distance as opposed to being accessed within a web browser, from two feet away, with a mouse and keyboard. This article explains how to make sure you get the best user experience for the 10-foot experience scenario.

Designing for TV and understanding the “TV SafeZone”

Television manufacturers will apply a “safe-zone” around the content that can clip your app. By default, we apply a safe border around your app to account for this, however you can ensure that your app takes the full screen size using following code:


var applicationView = Windows.UI.ViewManagement.ApplicationView.getForCurrentView();
applicationView.setDesiredBoundsMode(Windows.UI.ViewManagement.ApplicationViewBoundsMode.useCoreWindow);

Understanding and managing XY focus and navigation

You’ll want to consider your app’s ability to handle XY navigation by the user and disable the “Mouse Mode” that’s turned on by default for UWP apps. This is important because users’ main input method for Xbox One is a handheld controller. See here for more on how to work with XY focus and navigation. Use the following code to enable XY navigation using JavaScript:


navigator.gamepadInputEmulation = &amp;quot;keyboard&amp;quot;;

To enable directional navigation, you can use the TVJS library which is discussed below.

Considering your app’s appearance when another app is snapped

When users run an app on Xbox One, a second app may be ‘snapped’ to the right of the main app. When this is the case, the main app is considered to be in Fill Mode. While testing your app, open Cortana or another ‘snappable’ app to see how your app appears. You want to make sure your UI is still usable and has a graceful transition between Full Screen and Fill Mode. Implement an adaptive UI to make sure the user has the best experience for this scenario.

Integrate with the System Media Controls

If your app is a media app, it is important that your app responds to the media controls initiated by the user via the on-screen buttons, Cortana (typically through speech), the System Media Transport Controls in the nav pane or the Xbox and SmartGlass apps on other devices. Take a look at the MediaPlayer control from TVJS which automatically integrates with these controls or check out how to manually integrate with the System Media Transport Controls.

TVJS

TVJS is a collection of helper libraries that make it easier to build web applications for the TV. If you are building a hosted web app that will also run on the Xbox, TVJS can help add support for Directional navigation, as well as provide several controls that make it easier to interact with content on the TV.

DirectionalNavigation

Directional navigation is a feature that provides automatic two-dimensional navigation within the pages of your TV app. Apps won’t need to trap and handle navigation within their pages, or to explicitly specify all the valid focus targets for each element in the UI. With automatic focus handling, users can navigate around in an intuitive and robust way.

When users enter directional input to move from one element to another, the automatic focus algorithm looks at the set of potential focus targets, determines the next element to move to and then automatically sets the focus to that element. To determine the element to move to, the algorithm combines directional input, past focus history, and the physical layout of UI elements on the page.

To enable directional navigation, include the following script reference:

<script src=”directionalnavigation-1.0.0.0.js”></script>

By default, only a, button, input, select, and text area elements are considered focus-able. To make other elements focus-able, set a valid tab index on the element.

<div tabindex=”0″>This div is eligible for focus</div>

Make sure to check out the documentation to learn how to change the root element, set initial focus, how to override next focus, best ways to optimize controls for focus and how to customize the input. Don’t miss the samples as well that go through a lot of great examples.

Submitting your app to the Windows Store

Once you’re happy with the app after testing it on Xbox, it’s time to publish it to the Windows Store!

Depending on which route you took to build the app, the process is a little different on how you build the package for Store submission.

Xbox One and Hosted Web Apps are a great way to deliver your web application to millions of Xbox One users and enter the living room experience with minimal effort.

Wrap up

Make sure to check out the app source on our official GitHub repository, read through some of the resources provided, watch the event if you missed it and let us know what you think through the comments below or on twitter.

Next time we will release another app experience and go in-depth on how to build great Internet of Things experiences using the Universal Windows Platform and how to make them shine on the Xbox One.

Until then, happy coding!

Resources for Hosted Web Apps

Download Visual Studio to get started!

The Windows team would love to hear your feedback.  Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.

— Written by Jeff Burtoft, Principle Program Manager WDG/PAX

Background Audio and Cross Platform Development with Xamarin (App Dev on Xbox series)

We are back with yet another app, Backdrop, an open source sample media app developed to showcase a cross-device music experience. In this blog post, we will dive deep into the new background model in the Universal Windows Platform, and specifically focus on how to enable your application to continue playing audio in the background  across Windows 10 devices, including Xbox One, delivering a stellar customer experience. In addition, we will show you how we built Backdrop to be a cross platform application by using Xamarin to share code between Windows 10 and AppleTV. The source code for the application is available on GitHub right now so make sure to check it out.

If you missed the previous blog post from last week on Unity interop and app extensibility, make sure to check it out. We covered how to get started building great 2D and 3D experiences with Unity and XAML as well as how to make your apps work great with other apps on the platform. To read the other blog posts and watch the recordings from the App Dev on Xbox live event that started it all, visit the App Dev on Xbox landing page.

Backdrop

image1

Figure 1. Xbox One view

Backdrop is a sample music application that lets a group of friends collaborate on the music selection process and share their experience and music choices. A device is first chosen to be the host device where the music will be played. Then anyone is able to add and vote on tracks on their own device. Each friend can see the current playlist in real time and the progress of the current track on their own device. Each can vote on different tracks to set the order in which they will be played as well as suggest other tracks to be played.

The application has been written for the Universal Windows Platform (UWP) and tvOS by using Xamarin to share the majority of business logic, view models, playlist management, cloud and device communication. The UI, in turn, is written using the native controls and affordances of each platform. Using the shared project, additional platforms such as Android and iOS can easily be added.

image2

Figure 2. architectural diagram

Background audio

With the Windows Anniversary Update, a new single process model for playing background audio was introduced to simplify UWP development. Using MediaPlayer or MediaPlayerElement with the new model should make implementing background audio much easier than it was before.

Previously, your app was required to manage a background process in addition to your foreground app and then manually communicate state changes between the two processes. Under the new model, you simply add the background audio capability to your app manifest and your app will automatically continue playing audio when it moves to the background. You will use the two new application life cycle events, EnteredBackground and LeavingBackground, to find out when your app is entering and leaving the background.

Background audio in Backdrop

image3

Figure 3. Playing audio in background and System Media Transport Controls on Xbox One

Here is the step-by-step process for implementing background audio:

  • Add the Background Media Playback capability to your app manifest.
  • If your app disables the automatic integration of MediaPlayer with the System Media Transport Controls (SMTC), such as by setting the IsEnabled property to false, then you must implement manual integration with the SMTC in order to enable background media playback. You must also manually integrate with SMTC if you are using an API other than MediaPlayer, such as AudioGraph, to play audio if you want to have the audio continue to play when your app moves to the background.
  • While your app is in the background, you must stay under the memory usage limits set by the system for background apps.

Modifying the app manifest

To enable background audio, you must add the background media playback capability to the app manifest file, Package.appxmanifest. You can modify the app manifest file either by using the designer or manually.

To do this through the Microsoft Visual Studio designer, in Solution Explorer, open the designer for the application manifest by double-clicking the package.appxmanifest item.

  1. Select the Capabilities
  2. Select the Background Media Playback check box.

To set the capability by manually editing the app manifest xml, first make sure that the uap3 namespace prefix is defined in the Package element. If not, add it as shown below. [see code on GitHub]


&amp;lt;Package xmlns=&amp;quot;http://schemas.microsoft.com/appx/manifest/foundation/windows10&amp;quot; 
         xmlns:mp=&amp;quot;http://schemas.microsoft.com/appx/2014/phone/manifest&amp;quot; 
         xmlns:uap=&amp;quot;http://schemas.microsoft.com/appx/manifest/uap/windows10&amp;quot; 
         xmlns:uap3=&amp;quot;http://schemas.microsoft.com/appx/manifest/uap/windows10/3&amp;quot; 
         IgnorableNamespaces=&amp;quot;uap mp uap3&amp;quot;
         &amp;gt;

Then add the backgroundMediaPlayback capability to the Capabilities element:


  &amp;lt;Capabilities&amp;gt;
    &amp;lt;Capability Name=&amp;quot;internetClient&amp;quot; /&amp;gt;
    &amp;lt;uap3:Capability Name=&amp;quot;backgroundMediaPlayback&amp;quot; /&amp;gt;
  &amp;lt;/Capabilities&amp;gt;

System Media Transport Controls

image4

Figure 4. System Media Transport Controls on mobile

The Backdrop client uses a MediaPlayer to play audio in the PlaybackService class [see code on GitHub].


        public PlaybackService()
        {
            // Create the player instance
            _player = new MediaPlayer();
            _player.PlaybackSession.PositionChanged += PlaybackSession_PositionChanged;
            _player.PlaybackSession.PlaybackStateChanged += PlaybackSession_PlaybackStateChanged;

            _playlist = new MediaPlaybackList();
            _playlist.CurrentItemChanged += _playlist_CurrentItemChanged;
            _player.Source = _playlist;
            _player.Play();

            Dispatcher = new DispatcherWrapper(CoreApplication.MainView.CoreWindow.Dispatcher);

When using a MediaPlayer, it is necessary to implement MediaTransportControls. The media transport controls let users interact with their media by providing a default playback experience comprised of various buttons including play, pause, closed captions and others.

When adding audio tracks to the player, you also need to create a MediaPlaybackItem from the audio source and set its display properties in order to play it. Here is the code from Backdrop [see code on GitHub]:


    var source = MediaSource.CreateFromUri(new Uri(song.StreamUrl));

    var playbackItem = new MediaPlaybackItem(source);
    var displayProperties = playbackItem.GetDisplayProperties();
    displayProperties.Type = Windows.Media.MediaPlaybackType.Music;
    displayProperties.MusicProperties.Title = song.Title;
    displayProperties.MusicProperties.Artist = song.Artist;
    displayProperties.Thumbnail = RandomAccessStreamReference.CreateFromUri(new Uri(song.AlbumArt));

    playbackItem.ApplyDisplayProperties(displayProperties);

You can also override the default SMTC controls and even use manual control if you are using your own media playback. MediaTransportControls is ultimately just a composite control made up of several other XAML controls, which are all contained within a root Grid element. Because of this, you can re-template the control to change its appearance and functionality. For more info, see Create custom transport controls and the Media transport controls sample.

Managing resources in background

When your app moves from the foreground to the background, the EnteredBackground event is raised. And when your app returns to the foreground, the LeavingBackground event is raised. Because these are app life cycle events, you should register handlers for these events when your app is created. In the default project template, this means adding it to the App class constructor in App.xaml.cs.

Because running in the background will reduce the memory resources your app is allowed to retain by the system, you should also register for the AppMemoryUsageIncreased and AppMemoryUsageLimitChanging events, which will be used to check your app’s current memory usage and the current limit. The handlers for these events are shown in the following examples. For more information about the application lifecycle for UWP apps, see App life cycle. You can see the code from Backdrop here [see code on GitHub]:


private void App_LeavingBackground(object sender, LeavingBackgroundEventArgs e)
        {
            _isInBackgroundMode = false;

            // Reastore view content if it was previously unloaded.
            if (Window.Current.Content == null)
            {
                CreateRootFrame(ApplicationExecutionState.Running, string.Empty);
            }
        }

        private void App_EnteredBackground(object sender, EnteredBackgroundEventArgs e)
        {
            _isInBackgroundMode = true;
            ReduceMemoryUsage(0);
        }

When your app transitions to the background, the memory limit for the app is reduced by the system in order to ensure that the current foreground app has sufficient resources to provide a responsive user experience. The AppMemoryUsageLimitChanging event handler lets your app know that its allotted memory has been reduced and provides the new limit in the event args passed into the handler. [see code on GitHub]


        private void MemoryManager_AppMemoryUsageIncreased(object sender, object e)
        {
            var level = MemoryManager.AppMemoryUsageLevel;

            if (level == AppMemoryUsageLevel.OverLimit || level == AppMemoryUsageLevel.High)
            {
                ReduceMemoryUsage(MemoryManager.AppMemoryUsageLimit);
            }
        }

        private void MemoryManager_AppMemoryUsageLimitChanging(object sender, AppMemoryUsageLimitChangingEventArgs e)
        {
            if (MemoryManager.AppMemoryUsage &amp;gt;= e.NewLimit)
            {
                ReduceMemoryUsage(e.NewLimit);
            }
        }

Xamarin

Xamarin is a free Microsoft tool that allows developers to write fully native Android and iOS apps using C# and programming models already familiar to .NET developers. With Xamarin, you can build native Android and iOS apps without needing to know Java or Objective-C and best of all it is included with all editions of Visual Studio 2015. For Android development, Visual Studio has one of the most performant Android emulators built in so you can test your Xamarin.Android apps from your Windows development environment. For iOS development, Xamarin provides a remote iOS simulator for Visual Studio to test your applications without having to switch to a Mac. It even supports touch and multi-touch; something that is missing from testing iOS apps on the iOS simulator on a Mac. You will still need to connect to a physical Mac in order to build the application, but the entire development process is completely done in Visual Studio, including editing storyboards.

Apps built using Xamarin compile to native code on their respective platforms. Xamarin wraps low level native APIs so you are able to access sensors and other platform specific features. Xamarin.iOS projects compile to .app files that can be deployed to Apple mobile devices. Xamarin.Android projects compile to .apk files, the application package used for deploying to Android devices.

image5

Because Xamarin lets you use Visual Studio projects to organize your Xamarin.Android and Xamarin.iOS code, you can include different platform versions of your app side-by-side under a common solution. When you do this, it is important to clearly separate your UI code from your business layer code. It is also important to separate out any code you intend to share between platforms from code that is platform-specific.

Sharing code with Xamarin

Xamarin provides two ways of sharing business layer code between your cross-platform projects. You can use either a Shared Project or a Portable Class Library (PCL). Each has its advantages and disadvantages.

A Shared Project is generally the easier way to create common code. The .cs files in a Shared Project simply get included as part of any project that references it. On build, the Shared Project is not compiled into a DLL. Instead, the Shared Project’s code files are compiled into the output for the referencing project. Shared Projects become tricky when they include platform specific code. You will need to use conditional compilation directives like #if and #endif in these situations to test for the appropriate compiler version.

Unlike Shared Projects, Portable Class Library projects are compiled into DLLs. You decide which platforms your PCL can run on by setting its Profile identifier. For instance, you might have your PCL target all of the following: .NET Framework 4.5, ASP.NET Core 1.0, Xamarin.Android, Xamarin.iOS and Windows 8. PCLs use conditional compilation directives in order to fork platform specific code. Instead, you may want to use a Dependency Injection pattern with multiple PCLs for this.

The Backdrop reference app uses a PCL for sharing common code between a UWP app, a tvOS app for the Apple TV, and music_appService—a RESTful web service consumed by both.

image6

Building the UI

Each platform needs to have its own UI project. You can choose, however, to share common visual elements using the Xamarin.Forms cross-platform UI library, or create custom UIs for each platform. Both options will create fully-native UIs that will be completely familiar to end-users, but Xamarin.Forms is more restrictive. Developers seeking the greatest amount of code-sharing and efficiency will gravitate toward Xamarin.Forms, while those who require a more granular level of control should choose Xamarin.Android and Xamarin.iOS for a custom UI. The Backdrop reference app uses custom UIs.

You are probably already familiar with how to create a native UWP UI, either in Xaml or with the Visual Studio designer. You will be glad to learn that Visual Studio comes with a Xamarin Designer for iOS that provides a similarly easy way for you to work with native iOS controls. The iOS Designer maintains full compatibility with the Storyboard and .xib formats, so that files can be edited in either Visual Studio or Xcode’s Interface Builder.

image7

Wrap up

Adding other platforms is straightforward and can be an exercise for the reader. We implemented tvOS and UWP apps, but the same shared code can be used in iOS and Android projects just as easily. The cross-platform architecture demonstrated in the Backdrop source code provides a great way to achieve the greatest reach with a single, maintainable cross-platform code base. It also shows us how the cross-platform story for UWP and the cross-platform story for Xamarin actually dovetail to create apps with much greater reach than we have ever seen before. Consider that Backdrop’s architectural design ultimately allows friends on an android phone, an iPhone, a Windows 10 phone, Apple TV and Xbox One to all work together on a common music playlist. How’s that for a build-once solution?

Until next time…

…check out the app source on our official GitHub repository, read through some of the resources provided, watch the event if you missed it, and let us know what you think through the comments below or on twitter.

Next week we will release another app experience and go in-depth on how to build hosted web experiences that take advantage of native platform functionality and different input modalities across UWP and other native platforms.

Until then, happy coding!

Resources

In the meantime, below are some additional resources to help you understand background audio as well as the architectural underpinnings of modern cross-platform apps build with Xamarin.

Download Visual Studio to get started!

The Windows team would love to hear your feedback.  Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.

MIDI Enhancements in Windows 10

As Windows 10 evolves, we are continuing to build in support for musician-focused technologies.

Let’s take a look at MIDI. Windows has had built-in MIDI support going back to the 16-bit days. Since then, most MIDI interfaces have moved to USB and our in-box support has kept pace, with a class driver and APIs that support those new interfaces.

Those unfamiliar with music technology may think of MIDI as just .mid music files. But that’s only a tiny part of what MIDI really is. Since its standardization in 1983, MIDI has remained the most used and arguably most important communications protocol in music production. It’s used for everything from controlling synthesizers and sequencers and changing patches for set lists, to synchronizing mixers and even switching cameras on podcasts using a MIDI control surface. Even the Arduino Firmata protocol is based on MIDI.

In this post, we’ll talk about several new things we’ve created to make MIDI even more useful in your apps:

  • UWP MIDI Basics – using MIDI in Windows Store apps
  • New Bluetooth LE MIDI support in Windows 10 Anniversary Update
  • The Win32 wrapper for UWP MIDI (making the API accessible to desktop apps)
  • MIDI Helper libraries for C# and PowerShell

In addition, we included a number of audio-focused enhancements when Windows 10 was released last summer. These enhancements included: low-latency improvements to WASAPI, additional driver work with partners to opt-in to smaller buffers for lower latency on modern Windows 10 devices like Surface and phones like the 950/950xl; tweaks to enable raw audio processing without any latency-adding DSP; a new low-latency UWP Audio and effects API named AudioGraph; and, of course, a new UWP MIDI API.

We’ve also recently added support for spatial audio for immersive experiences. This past fall, in the 1511 update, we enabled very forward-looking OS support for Thunderbolt 3 Audio devices, to ensure we’re there when manufacturers begin creating these devices and their high performance audio drivers. Cumulatively, this was a lot of great work by Windows engineering, all targeting musicians and music creation apps.

UWP MIDI Basics

In Windows 10 RTM last year we introduced a new MIDI API, accessible to UWP Apps on virtually all Windows 10 devices, which provides a modern way to access these MIDI interfaces. We created this API to provide a high performance and flexible base upon which we can build support for new MIDI interfaces.

We originally put this API out for comment as a NuGet package in Windows 8.1 and received a lot of feedback from app developers. What you see in Windows 10 is a direct result of that feedback and our testing.

The API plugs in nicely with the device enumeration and watcher APIs in UWP, making it easy to detect hot plug/unplug of devices while your app is running.

Here’s a simple way to get a list of MIDI devices and their IDs, using C#:


using Windows.Devices.Midi;
using Windows.Devices.Enumeration;
...
private async void ListMidiDevices()
{
    // Enumerate Input devices

    var deviceList = await DeviceInformation.FindAllAsync(
             MidiInPort.GetDeviceSelector());

    foreach (var deviceInfo in deviceList)
    {
        System.Diagnostics.Debug.WriteLine(deviceInfo.Id);
        System.Diagnostics.Debug.WriteLine(deviceInfo.Name);
        System.Diagnostics.Debug.WriteLine(&amp;quot;----------&amp;quot;);
    }

    // Output devices are enumerated the same way, but 
    // using MidiOutPort.GetDeviceSelector()
}

And here’s how to set up a watcher and handle enumeration/watcher events, and also get the list of connected interfaces. This is a bit more code, but it’s a more appropriate approach for most apps:


private void StartWatchingInputDevices()
{
    var watcher = DeviceInformation.CreateWatcher(
                     MidiInPort.GetDeviceSelector());

    watcher.Added += OnMidiInputDeviceAdded;
    watcher.Removed += OnMidiInputDeviceRemoved;
    watcher.EnumerationCompleted += OnMidiInputDeviceEnumerationCompleted;

    watcher.Start();
}

private void OnMidiInputDeviceEnumerationCompleted(
    DeviceWatcher sender, object args)
{
    // Initial enumeration is complete. This is when
    // you might present a list of interfaces to the
    // user of your application.
}

private void OnMidiInputDeviceRemoved(
    DeviceWatcher sender, DeviceInformationUpdate args)
{
    // handle the removal of a MIDI input device
}

private void OnMidiInputDeviceAdded(
    DeviceWatcher sender, DeviceInformation args)
{
    // handle the addition of a new MIDI input device
}

Using a watcher for listing devices and handling add/remove is a best practice to follow in your apps. No one wants to restart their app just because they forgot to plug in or turn on their MIDI controller. Using the watcher makes it easy for your app to appropriately handle those additions/removals at runtime.

The API is simple to use, with strongly typed classes for all standard messages, as well as support for SysEx and buffer-based operations. This C# example shows how to open input and output ports, and respond to specific MIDI messages.


using Windows.Devices.Midi;
using Windows.Devices.Enumeration;
...
private async void MidiExample()
{
    string outPortId = &amp;quot;id you get through device enumeration&amp;quot;;
    string inPortId = &amp;quot;id you get through device enumeration&amp;quot;;

    // open output port and send a message
    var outPort = await MidiOutPort.FromIdAsync(outPortId);
    var noteOnMessage = new MidiNoteOnMessage(0, 110, 127);
    outPort.SendMessage(noteOnMessage);

    // open an input port and listen for messages
    var inPort = await MidiInPort.FromIdAsync(inPortId);
    inPort.MessageReceived += OnMidiMessageReceived;
}

private void OnMidiMessageReceived(MidiInPort sender, 
                         MidiMessageReceivedEventArgs args)
{
    switch (args.Message.Type)
    {
        case MidiMessageType.NoteOn:
            break;
        case MidiMessageType.PolyphonicKeyPressure:
            break;
        // etc.
    }
}

In most cases, you would inspect the type of the message, and then cast the IMidiMessage to one of the strongly-typed messages defined in the Windows.Devices.Midi namespace, such as MidiNoteOnMessage or MidiPitchBendChangeMessage. You’re not required to do this, however; you can always work from the raw data bytes if you prefer.

The Windows 10 UWP MIDI API is suitable for creating all kinds of music-focused Windows Store apps. You can create control surfaces, sequencers, synthesizers, utility apps, patch librarians, lighting controllers, High Voltage Tesla Coil Synthesizers and much more.

Just like the older MIDI APIs, the Windows 10 UWP MIDI API works well with third-party add-ons such as Tobias Erichsen’s great rtpMIDI driver, providing support for MIDI over wired and Wi-Fi networking.

One great feature of the new API is that it is multi-client. As long as all apps with the port open are using the Windows 10 UWP MIDI API and not the older Win32 MME or DirectMusic APIs, they can share the same device. This is something the older APIs don’t handle without custom drivers and was a common request from our partners and customers.

Finally, it’s important to note that the Windows 10 UWP MIDI API works with all recognized MIDI devices, whether they use class drivers or their own custom drivers. This includes many software-based MIDI utilities implemented as drivers on Windows 10.

New Bluetooth LE MIDI support in UWP MIDI

In addition to multi-client support and the improvements we’ve made in performance and stability, a good reason to use the Windows 10 UWP MIDI API is because of its support for new standards and transports.

Microsoft actively participates in the MIDI standards process and has representatives in the working groups. There are several of us inside Microsoft who participate directly in the creation, vetting and voting of standards for MIDI, and for audio in general.

One exciting and relatively new MIDI standard which has been quickly gaining popularity is Bluetooth LE MIDI. Microsoft voted to ratify the standard based upon the pioneering work that Apple did in this space; as a result, Apple, Microsoft and others are compatible with a standard that is seeing real traction in the musician community, and already has a number of compatible peripherals.

In Windows 10 Anniversary Edition, we’ve included in-box support for Bluetooth LE MIDI for any app using the Windows 10 UWP MIDI API.

In Windows 10 Anniversary Edition, we’ve included in-box support for Bluetooth LE MIDI for any app using the Windows 10 UWP MIDI API. This is an addition which requires no changes to your code, as the interface itself is simply another transparent transport surfaced by the MIDI API.

This type of MIDI interface uses the Bluetooth radio already in your PC, Phone, IoT device or other Windows 10 device to talk to Bluetooth MIDI peripherals such as keyboards, pedals and controllers. Currently the PC itself can’t be a peripheral, but we’re looking at that for the future. Although there are some great DIN MIDI to Bluetooth LE MIDI and similar adapters out there, no additional hardware is required for Bluetooth LE MIDI in Windows 10 as long as your PC has a Bluetooth LE capable radio available.

We know latency is important to musicians, so we made sure our implementation is competitive with other platforms. Of course, Bluetooth has higher latency than a wired USB connection, but that tradeoff can be worth it to eliminate the cable clutter.

When paired, the Bluetooth LE MIDI peripheral will show up as a MIDI device in the device explorer, and will be automatically included in the UWP MIDI device enumeration. This is completely transparent to your application.

For more information on how to discover and pair devices, including Bluetooth LE MIDI devices, please see the Device Enumeration and Pairing example on GitHub.

We added this capability in Windows 10 Anniversary Edition as a direct result of partner and customer feedback. I’m really excited about Bluetooth LE MIDI in Windows 10 and the devices which can now be used on Windows 10.

image1

Desktop application support for the UWP MIDI API

We know that the majority of musicians use desktop Win32 DAWs and utilities when making music. The UWP MIDI API is accessible to desktop applications, but we know that accessing UWP APIs from different languages and build environments can be challenging.

To help desktop app developers with the new API and to reduce friction, my colleague Dale Stammen on our WDG/PAX Spark team put together a Win32 wrapper for the Windows 10 UWP MIDI API.

The work our team does, including this API wrapper, is mostly partner-driven. That means that as a result of requests and feedback, we create things to enable partners to be successful on Windows. One of the partners we worked with when creating this is Cakewalk, makers of the popular SONAR desktop DAW application.

This is what their developers had to say about the Win32 wrapper for the UWP MIDI API, and our support for Bluetooth LE MIDI:

“We’re happy to see Microsoft supporting the Bluetooth MIDI spec and exposing it to Windows developers through a simplified API. Using the new Win32 wrapper for the UWP MIDI API, we were able to prototype Bluetooth MIDI support very quickly.  
At Cakewalk we’re looking ahead to support wireless peripherals, so this is a very welcome addition from Microsoft.”

—  Noel Borthwick, CTO, Cakewalk

 

image2

We love working with great partners like Cakewalk, knowing that the result will directly benefit our mutual customers.

This Win32 wrapper makes it simple to use the API just like any flat Win32 API. It surfaces all the capabilities of the Windows 10 UWP MIDI API, and removes the requirement for your Win32 application to be UWP-aware. Additionally, there’s no requirement to use C++/CX or otherwise change your build tools and processes. Here’s a C++ Win32 console app example:


// open midi out port 0
result = gMidiOutPortOpenFunc(midiPtr, 0, &amp;amp;gMidiOutPort);
if (result != WINRT_NO_ERROR)
{
	cout &amp;lt;&amp;lt; &amp;quot;Unable to create Midi Out port&amp;quot; &amp;lt;&amp;lt; endl;
	goto cleanup;
}

// send a note on message to the midi out port
unsigned char buffer[3] = { 144, 60 , 127 };
cout &amp;lt;&amp;lt; &amp;quot;Sending Note On to midi output port 0&amp;quot; &amp;lt;&amp;lt; endl;
gMidiOutPortSendFunc(gMidiOutPort, buffer, 3);

Sleep(500);

// send a note off message to the midi out port
cout &amp;lt;&amp;lt; &amp;quot;Sending Note Off to midi output port 0&amp;quot; &amp;lt;&amp;lt; endl;
buffer[0] = 128;
gMidiOutPortSendFunc(gMidiOutPort, buffer, 3); 

This API is optimized for working with existing Win32 applications, so we forgo strongly typed MIDI messages and work instead with byte arrays, just like Win32 music app developers are used to.

We’re still getting feedback from partners and developers on the API wrapper, and would love yours. You can find the source code on GitHub. We may change the location later, so the aka.ms link ( http://aka.ms/win10midiwin32 ) is the one you want to keep handy.

For developers using recent versions of Visual Studio, we’ve also made available a handy NuGet package.

We’re already working with desktop app partners to incorporate into their applications this API using this wrapper, as well as other audio and user experience enhancements in Windows 10. If you have a desktop app targeting pro musicians and have questions, please contact me at @pete_brown on Twitter, or pete dot brown at Microsoft dot com.

MIDI Helper libraries for Windows Store apps

In addition to the Win32 API wrapper, we also have some smaller helper libraries for store app developers and PowerShell users.

The first is my Windows 10 UWP MIDI API helper, for C#, VB, and C++ Windows Store apps. This is designed to make it easier to enumerate MIDI devices, bind to the results in XAML and respond to any hot plug/unplug changes. It’s available both as source and as a compiled NuGet package.

It includes a watcher class with XAML-friendly bindable / observable collections for the device information instances.

RPN and NRPN Messages

Additionally, the helper library contains code to assist with RPN (Registered Parameter Number) and NRPN (Non-Registered Parameter Number) messages. These can be more challenging for new developers to work with because they are logical messages comprised of several different messages aggregated together, sent in succession.

image3

Because we exposed the Windows.Devices.Midi.IMidiMessage interface in UWP, and the underlying MIDI output code sends whatever is in the buffer, creating strongly typed aggregate message classes was quite easy. When sending messages, you use these classes just like any other strongly typed MIDI message.

I’m investigating incorporating support for the proposed MPE (Multidimensional Polyphonic Expression), as well as for parsing and aggregating incoming RPN and NRPN messages. If these features would be useful to you in your own apps, please contact me and let me know.

MIDI Clock Generator

One other piece the library includes is a MIDI clock generator. If you need a MIDI clock generator (not for a sequencer control loop, but just to produce outgoing clock messages), the library contains an implementation that you will find useful. Here’s how you use it from C#:


private MidiClockGenerator _clock = new MidiClockGenerator();

...
_clock.SendMidiStartMessage = true;
_clock.SendMidiStopMessage = true;

...


foreach (DeviceInformation info in deviceWatcher.OutputPortDescriptors)
{
    var port = (MidiOutPort)await MidiOutPort.FromIdAsync(info.Id);

    if (port != null)
        _clock.OutputPorts.Add(port);
}

...

public void StartClock()
{
    _clock.Start();
}

public void StopClock()
{
    _clock.Stop();
}

public double ClockTempo
{
    get { return _clock.Tempo; }
    set
    {
        _clock.Tempo = value;
    }
}

My GitHub repo includes the C++/CX source and a C#/XAML client app. As an aside: This was my first C++/CX project. Although I still find C# easier for most tasks, I found C++ CX here quite approachable. If you’re a C# developer who has thought about using C++ CX, give it a whirl. You may find it more familiar than you expect!

This library will help developers follow best practices for MIDI apps in the Windows Store. Just like with desktop apps, if you’re building a musician-focused app here and have questions, please contact me at @pete_brown on Twitter, or pete dot brown at Microsoft dot com.

The second helper library is a set of PowerShell commands for using the Windows 10 UWP MIDI API. I’ve talked with individuals who are using this to automate scripting of MIDI updates to synchronize various mixers in a large installation and others who are using it as “glue” for translating messages between different devices. There’s a lot you can do with PowerShell in Windows 10, and now MIDI is part of that. The repo includes usage examples, so I won’t repeat that here.

Conclusion

I’m really excited about the work we continue to do in the audio space to help musicians and music app developers on Windows.

Altogether, the UWP MIDI API, the Win32 wrapper for the UWP MIDI API, and the helper libraries for Windows Store apps and for PowerShell scripting make it possible for apps and scripts to take advantage of the latest MIDI tech in Windows 10, including Bluetooth MIDI.

I’m really looking forward to the upcoming desktop and Windows Store apps which will support this API, and technologies like Bluetooth LE MIDI. And, as I mentioned above, please contact me directly if you’re building a pro musician-targeted app and need guidance or otherwise have questions.

Resources

Download Visual Studio to get started.

The Windows team would love to hear your feedback.  Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.

Smooth Interaction and Motion with the Visual Layer

The Composition APIs come with a robust animation engine that provides quick and fluid motion running in a separate process from your Universal Windows Platform (UWP) app. This provides a consistent 60 frames per second when running your app on an IoT device as well as on a screaming gaming machine. It is, quite simply, fast.

blogpost4-1

The Composition APIs also provide something you probably have never had access to before: the ability to create high-performing, low-level manipulation-driven custom animations like the one shown above.  Preview releases of the Composition APIs have already given you the ability to control animations with the XAML ScrollViewer’s ManipulationPropertySet. The Windows 10 Anniversary Update allows you to go even further, with the goal of empowering developers to use many types of input to drive animation.

This post will briefly cover the basics of expression animations. It will move on to a demonstration of how to drive expression animations from a ScrollViewer ManipulationPropertySet and, more importantly, why you really want to even if you don’t realize it yet. Finally, it will touch on the new InteractionTracker and give you an indication of just how much more powerful you are today as a developer than you were at the end of July.

A fast and fluid overview of expression animations

The Visual Layer supports both keyframe animations as well as expression animations. If you have worked with XAML animations before, then you are probably already familiar with how keyframes work. In a keyframe animation, you set values for some property you want to change over time and also assign the duration for the change: in the example below, a start value, a middle value, and then an ending value. The animation system will take care of tweening your animation – in other words, generating all the values between the ones you have explicitly specified.


ScalarKeyFrameAnimation blurAnimation = _compositor.CreateScalarKeyFrameAnimation();
blurAnimation.InsertKeyFrame(0.0f, 0.0f);
blurAnimation.InsertKeyFrame(0.5f, 100.0f);
blurAnimation.InsertKeyFrame(1.0f, 0.0f);
blurAnimation.Duration = TimeSpan.FromSeconds(4);
blurAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
_brush.StartAnimation(&amp;quot;Blur.BlurAmount&amp;quot;, blurAnimation);

A keyframe animation is a fire-and-forget mechanism that is time based. There are situations, however, when you need your animations to be coordinated and actually driving each other instead of simply moving in synchronized fashion.

blogpost4-2

In the demo above (source code), each gray gear is animated based on the animation of the gear preceding it. If the preceding gear suddenly goes faster or reverses direction, it forces the following gear to do the same. A keyframe animations can’t create motion effects that work in this way, but expression animations can. They are able to do so because, while keyframe animations are time based, expression animations are reference based.

The critical code that hooks up the gears for animation in the demo is found in the following section that calls the CreateExpressionAnimation method on the Compositor instance. The expression basically says that the animation should reference and be driven by the RotationAngleInDegrees property of the Visual that is indicated by the parameter “previousGear”. In the next line, the reference parameter is assigned. In the final line, the current Visual’s RotationAngleInDegrees property is finally animated based on the value referred to in the ExpressionAnimation object.


private void ConfigureGearAnimation(Visual currentGear, Visual previousGear)
{
    // If rotation expression is null then create an expression of a gear rotating the opposite direction
    _rotationExpression = _rotationExpression ?? _compositor.CreateExpressionAnimation(&amp;quot;-previousGear.RotationAngleInDegrees&amp;quot;);

    // put in placeholder parameters
    _rotationExpression.SetReferenceParameter(&amp;quot;previousGear&amp;quot;, previousGear);

    // Start the animation based on the Rotation Angle in Degrees.
    currentGear.StartAnimation(&amp;quot;RotationAngleInDegrees&amp;quot;, _rotationExpression);
}

But if an animation can be driven by another animation, you may be wondering, couldn’t we also drive an animation with something more concrete like user input? Why, yes. Yes, we can.

The beauty of the ScrollViewer ManipulationPropertySet

Driving an animation from a ScrollViewer using XAML-Composition interop is fairly easy. With just a few lines of code, you can add an animation to a pre-existing ScrollViewer control by taking advantage of the GetScrollViewerManipulationPropertySet method on the ElementCompositionPreview class.

You would use this technique if you wanted to add a parallax effect to your XAML or to create a sticky header that stays in place as content scrolls beneath it. In the demo illustrated below (source code), a ScrollViewer is even used to drive a parallax effect on a ListView.

blogpost4-3

Adding parallax behavior to a XAML page can be accomplished in just a few lines, as the following sample code by James Clarke demonstrates.


CompositionPropertySet scrollerManipProps = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(myScroller);

Compositor compositor = scrollerManipProps.Compositor;

// Create the expression
ExpressionAnimation expression = compositor.CreateExpressionAnimation(&amp;quot;scroller.Translation.Y * parallaxFactor&amp;quot;);

// wire the ParallaxMultiplier constant into the expression
expression.SetScalarParameter(&amp;quot;parallaxFactor&amp;quot;, 0.3f);

// set &amp;quot;dynamic&amp;quot; reference parameter that will be used to evaluate the current position of the scrollbar every frame
expression.SetReferenceParameter(&amp;quot;scroller&amp;quot;, scrollerManipProps);

// Get the background image and start animating it's offset using the expression
Visual backgroundVisual = ElementCompositionPreview.GetElementVisual(background);
backgroundVisual.StartAnimation(&amp;quot;Offset.Y&amp;quot;, expression);

The even more beautiful InteractionTracker

Driving expression animations with a ScrollViewer is extremely powerful, but what if you want to drive animations using touch gestures instead? What if you want to pull items toward you with your finger, as in the demo below (source code), or animate multiple flying images across and into the screen as happens in the demo at the top of this post (source code)?

blogpost4-4

In order to achieve these effects, you would use the new InteractionTracker and VisualInteractionSource classes. InteractionTracker is a state machine that can be driven by active input. This is what you hook up to your animations. The VisualInteractionSource class, on the other hand, determines what kind of input you will use to drive your InteractionTracker.

picture5

The following sample code demonstrates a basic implementation of an InteractionTracker that is driven by touch input. The viewportVisual is simply the backing Visual for the root element on the page. You use this as the VisualInteractionSource for the tracker. In doing so, you specify that you are tracking X and Y manipulations. You also indicate that you want to track inertial movement.


_tracker = InteractionTracker.Create(_compositor);

var interactionSource = VisualInteractionSource.Create(viewportVisual);

interactionSource.PositionXSourceMode = InteractionSourceMode.EnabledWithInertia;
interactionSource.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia;

_tracker.InteractionSources.Add(interactionSource);

Hooking the tracker up to an expression animation works basically the same way as hooking up a gear Visual to another gear Visual, as you did earlier. You call the CreateExpressionAnimation factory method on the current Compositor and reference the Position property of the tracker. You then animate the Offset property of the Visual you want to add motion to your expression.


var positionExpression = _compositor.CreateExpressionAnimation(&amp;quot;-tracker.Position&amp;quot;);
positionExpression.SetReferenceParameter(&amp;quot;tracker&amp;quot;, _tracker);

contentVisual.StartAnimation(&amp;quot;Offset&amp;quot;, positionExpression);


Those are the basics of driving animation from almost any input. What you do with this amazing new power is entirely up to you.

Wrapping up

Expression animations and Visual Layer Interactions are both topics that can become very deep, very fast. To help you through these deeper waters, we highly recommend the following videos and articles:

Get started now – download Visual Studio.

The Windows team would love to hear your feedback. Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.