/// <summary>
        /// Checks if our "currently playing" and "fullscreen content" states still fit to the
        /// appropriate players, i.e. if we are in a "currently playing" state and the current player context was
        /// changed, the workflow state will be adapted to match the new current player context's "currently playing" state.
        /// The same check will happen for the primary player context and the "fullscreen content" state.
        /// </summary>
        /// <remarks>
        /// This method must not be called when the player manager's lock is held.
        /// </remarks>
        protected void CheckMediaWorkflowStates_NoLock()
        {
            ISystemStateService sss = ServiceRegistration.Get <ISystemStateService>();

            if (sss.CurrentState != SystemState.Running)
            {
                // Only automatically change workflow states in running state
                return;
            }
            IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>();

            workflowManager.StartBatchUpdateAsync();
            ILogger        log           = ServiceRegistration.Get <ILogger>();
            IPlayerManager playerManager = ServiceRegistration.Get <IPlayerManager>();

            try
            {
                for (int i = 0; i < _playerWfStateInstances.Count; i++)
                {
                    // Find the first workflow state of our cached player workflow states which doesn't fit any more
                    // and update to the new player workflow state of the same player workflow state type, if necessary.
                    PlayerWFStateInstance wfStateInstance = _playerWfStateInstances[i];
                    Guid?  newStateId;
                    string stateName;
                    switch (wfStateInstance.WFStateType)
                    {
                    case PlayerWFStateType.CurrentlyPlaying:
                        newStateId = GetPotentialCPStateId();
                        stateName  = "Currently Playing";
                        break;

                    case PlayerWFStateType.FullscreenContent:
                        newStateId = GetPotentialFSCStateId();
                        stateName  = "Fullscreen Content";
                        break;

                    default:
                        throw new NotImplementedException(string.Format("No handler for player workflow state type '{0}'",
                                                                        wfStateInstance.WFStateType));
                    }
                    if (newStateId != wfStateInstance.WFStateId)
                    {
                        // Found the first player workflow state which doesn't fit any more
                        log.Debug("PlayerContextManager: {0} Workflow State '{1}' doesn't fit any more to the current situation. Leaving workflow state.",
                                  stateName, wfStateInstance.WFStateId);
                        lock (playerManager.SyncObj)
                            // Remove all workflow states until the player workflow state which doesn't fit any more
                            _playerWfStateInstances.RemoveRange(i, _playerWfStateInstances.Count - i);
                        workflowManager.NavigatePopToStateAsync(wfStateInstance.WFStateId, true);
                        if (newStateId.HasValue)
                        {
                            log.Debug("PlayerContextManager: Auto-switching to new {0} Workflow State '{1}'",
                                      stateName, newStateId.Value);
                            workflowManager.NavigatePushAsync(newStateId.Value);
                        }
                        break;
                    }
                }
            }
            finally
            {
                workflowManager.EndBatchUpdateAsync();
            }
        }
        protected void LeavePartyMode()
        {
            IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>();

            workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_PARTY_MUSIC_PLAYER, true);
        }
        protected void Update()
        {
            ISystemStateService sss = ServiceRegistration.Get <ISystemStateService>();

            if (sss.CurrentState != SystemState.Running)
            {
                return;
            }
            INotificationService notificationService = ServiceRegistration.Get <INotificationService>();
            int numNotifications             = notificationService.Notifications.Count;
            IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>();

            if (numNotifications == 0 && workflowManager.CurrentNavigationContext.WorkflowState.StateId == Consts.WF_STATE_ID_WATCH_NOTIFICATIONS)
            {
                // Don't pop the watch-notifications state from the navigation stack if we are in a sub state
                workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_WATCH_NOTIFICATIONS, true);
            }
            IsNotificationsHintVisible         = !workflowManager.IsStateContainedInNavigationStack(Consts.WF_STATE_ID_WATCH_NOTIFICATIONS) && numNotifications > 0;
            NumNotificationsTotal              = numNotifications;
            IsNotificationsAvailable           = numNotifications > 0;
            IsMoreThanOneNotificationAvailable = numNotifications > 1;
            if (numNotifications <= 1)
            {
                NMoreNotificationsText = string.Empty;
            }
            else if (numNotifications == 2)
            {
                NMoreNotificationsText = LocalizationHelper.Translate(Consts.RES_ONE_MORE_NOTIFICATION);
            }
            else
            {
                NMoreNotificationsText = LocalizationHelper.Translate(Consts.RES_N_MORE_NOTIFICATIONS, numNotifications - 1);
            }
            INotification notification = notificationService.PeekNotification();

            CurrentNotification = notification;
            if (notification != null)
            {
                if (string.IsNullOrEmpty(notification.CustomIconPath))
                {
                    switch (notification.Type)
                    {
                    case NotificationType.UserInteractionRequired:
                        NotificationSymbolRelFilePath = Consts.REL_PATH_USER_INTERACTION_REQUIRED_ICON;
                        break;

                    case NotificationType.Info:
                        NotificationSymbolRelFilePath = Consts.REL_PATH_INFO_ICON;
                        break;

                    case NotificationType.Warning:
                        NotificationSymbolRelFilePath = Consts.REL_PATH_WARNING_ICON;
                        break;

                    case NotificationType.Error:
                        NotificationSymbolRelFilePath = Consts.REL_PATH_ERROR_ICON;
                        break;
                    }
                }
                else
                {
                    NotificationSymbolRelFilePath = notification.CustomIconPath;
                }
                HasSubWorkflow = notification.HandlerWorkflowState.HasValue;
            }
        }
        protected static void LeaveChooseEffectWorkflow()
        {
            IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>();

            workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_PLAYER_CHOOSE_EFFECT_MENU_DIALOG, true);
        }
        protected static void LeaveAudioMenuWorkflow()
        {
            IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>();

            workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_PLAYER_AUDIO_MENU_DIALOG, true);
        }
        /// <summary>
        /// Updates the menu items for the dialogs "DialogPlayerConfiguration" and "DialogChooseAudioStream"
        /// and closes the dialogs when their entries are not valid any more.
        /// </summary>
        protected void CheckUpdatePlayerConfigurationData()
        {
            IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>();

            lock (_syncObj)
            {
                if (_inPlayerConfigurationDialog)
                {
                    UpdatePlayerConfigurationMenu();
                    if (_playerConfigurationMenu.Count == 0)
                    {
                        // Automatically close player configuration dialog if no menu items are available any more
                        workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_PLAYER_CONFIGURATION_DIALOG, true);
                    }
                }
                if (_inChooseAudioStreamDialog)
                {
                    UpdateAudioStreamsMenu();
                    if (_audioStreamsMenu.Count <= 1)
                    {
                        // Automatically close audio stream choice dialog if less than two audio streams are available
                        workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_CHOOSE_AUDIO_STREAM_DIALOG, true);
                    }
                }
                if (_inPlayerSlotAudioMenuDialog)
                {
                    UpdatePlayerSlotAudioMenu();
                    if (_playerSlotAudioMenu.Count <= 1)
                    {
                        // Automatically close audio stream choice dialog if less than two audio streams are available
                        workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_PLAYER_AUDIO_MENU_DIALOG, true);
                    }
                }
                if (_inPlayerChooseGeometryMenuDialog)
                {
                    // Automatically close geometry choice dialog if current player is no video player
                    if (_playerGeometryMenuPlayerContext == null || !_playerGeometryMenuPlayerContext.IsActive ||
                        !(_playerGeometryMenuPlayerContext.CurrentPlayer is IVideoPlayer))
                    {
                        // Automatically close geometry stream choice dialog
                        workflowManager.NavigatePopToStateAsync(Consts.WF_STATE_ID_PLAYER_CHOOSE_GEOMETRY_MENU_DIALOG, true);
                    }
                    else
                    {
                        UpdatePlayerChooseGeometryMenu();
                    }
                }
                if (_inPlayerChooseEffectMenuDialog)
                {
                    // Automatically close Effect choice dialog if current player is no video player
                    if (_playerEffectMenuPlayerContext == null || !_playerEffectMenuPlayerContext.IsActive ||
                        !(_playerEffectMenuPlayerContext.CurrentPlayer is IVideoPlayer))
                    {
                        // Automatically close effect stream choice dialog
                        while (_inPlayerChooseEffectMenuDialog)
                        {
                            workflowManager.NavigatePop(1);
                        }
                    }
                    else
                    {
                        UpdatePlayerChooseEffectMenu();
                    }
                }
            }
        }