Defines the configuration for the SDK.
        /// <summary>
        /// Initializes the SDK using the given configuration. The scanner can be used separately, but
        /// the resolving beacon actions cannot be done unless the SDK is initialized.
        /// If background task is enabled, this method check if there are updates for the
        /// background task filters available and updates them if so.
        /// </summary>
        public async Task InitializeAsync(SdkConfiguration configuration)
        {
            Status.IsApiKeyValid = false;
            _logger.Debug("InitializeAsync");
            Configuration = configuration;

            SdkEngine.Configuration = configuration;


            if (!IsInitialized)
            {
                await SdkEngine.InitializeAsync();
                await InitializeSettingsAsync();

                Status.IsApiKeyValid   = ServiceManager.LayoutManager.IsLayoutValid;
                Scanner.StatusChanged += OnScannerStatusChanged;
                Scanner.BeaconEvent   += OnBeaconEventAsync;
            }

            if (SdkData.BackgroundTaskEnabled)
            {
                _logger.Debug("InitializeAsync#InitializeBackgground");
                await UpdateBackgroundTaskIfNeededAsync();
            }

            if (configuration.AutoStartScanner)
            {
                StartScanner();
            }
        }
 public void TestSetup()
 {
     ServiceManager.ReadOnlyForTests = false;
     ServiceManager.Clear();
     SdkConfiguration = new SdkConfiguration() {ApiKey = "1234567890"};
     ServiceManager.ApiConnction = new MockApiConnection()
     {
         MockSettings = "{\"revision\":0,\"settings\":{\"scanner.backgroundWaitTime\":120000, \"scanner.exitTimeoutMillis\":123, \"network.historyUploadInterval\":321}}",
         Configuration = SdkConfiguration,
         ValidApiKey = "1234567890"
     };
     ServiceManager.SettingsManager = new SettingsManager();
     ServiceManager.StorageService = new StorageService();
     ServiceManager.ReadOnlyForTests = true;
 }
        /// <summary>
        /// Registers the BLE advertisement watcher background task.
        /// </summary>
        /// <param name="configuration">Configuration for the new registration.</param>
        /// <returns>The registration result.</returns>
        private async Task <BackgroundTaskRegistrationResult> RegisterAdvertisementWatcherBackgroundTaskAsync(SdkConfiguration configuration)
        {
            BackgroundTaskRegistrationResult result = new BackgroundTaskRegistrationResult()
            {
                Success   = false,
                Exception = null
            };

            if (BackgroundTaskRegistered(AdvertisementClass))
            {
                // Already registered
                Logger.Debug("BackgroundTaskManager.RegisterAdvertisementWatcherBackgroundTask(): Already registered");
                result.Success = true;
            }
            else
            {
                BackgroundTaskBuilder backgroundTaskBuilder = new BackgroundTaskBuilder();

                backgroundTaskBuilder.Name           = AdvertisementClass + Guid.NewGuid();
                backgroundTaskBuilder.TaskEntryPoint = configuration.BackgroundAdvertisementClassName;

                BluetoothLEAdvertisementWatcherTrigger advertisementWatcherTrigger = new BluetoothLEAdvertisementWatcherTrigger();

                // This filter includes all Sensorberg beacons
                var pattern = BeaconFactory.UuidToAdvertisementBytePattern(configuration.BackgroundBeaconUuidSpace, configuration.ManufacturerId, configuration.BeaconCode);
                advertisementWatcherTrigger.AdvertisementFilter.BytePatterns.Add(pattern);

                ILayoutManager layoutManager = ServiceManager.LayoutManager;

                AppSettings = await ServiceManager.SettingsManager.GetSettings();

                // Using MaxSamplingInterval as SamplingInterval ensures that we get an event only
                // when entering or exiting from the range of the beacon
                advertisementWatcherTrigger.SignalStrengthFilter.SamplingInterval = advertisementWatcherTrigger.MaxSamplingInterval;
                if (AppSettings.RssiEnterThreshold != null && AppSettings.RssiEnterThreshold.Value >= -128 &&
                    AppSettings.RssiEnterThreshold.Value <= 127)
                {
                    advertisementWatcherTrigger.SignalStrengthFilter.InRangeThresholdInDBm = AppSettings.RssiEnterThreshold;
                }
                else
                {
                    advertisementWatcherTrigger.SignalStrengthFilter.InRangeThresholdInDBm = Constants.DefaultBackgroundScannerEnterThreshold;
                }

                advertisementWatcherTrigger.SignalStrengthFilter.OutOfRangeThresholdInDBm = SignalStrengthFilterOutOfRangeThresholdInDBm;
                advertisementWatcherTrigger.SignalStrengthFilter.OutOfRangeTimeout        = TimeSpan.FromMilliseconds(AppSettings.BeaconExitTimeout);

                IBackgroundTrigger trigger = advertisementWatcherTrigger;

                backgroundTaskBuilder.SetTrigger(trigger);

                try
                {
                    BackgroundTaskRegistration backgroundTaskRegistration = backgroundTaskBuilder.Register();
                    backgroundTaskRegistration.Completed += OnAdvertisementWatcherBackgroundTaskCompleted;
                    backgroundTaskRegistration.Progress  += OnAdvertisementWatcherBackgroundTaskProgress;

                    result.Success = true;
                }
                catch (Exception ex)
                {
                    result.Exception = ex;
                    Logger.Error("BackgroundTaskManager.RegisterAdvertisementWatcherBackgroundTask(): Failed to register: ", ex);
                    if (ex.Message.Contains("0x800710DF)"))
                    {
                        await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() => await new MessageDialog("Activate Bluetooth for the app").ShowAsync());
                    }
                }

                if (result.Success)
                {
                    // Check if there was a pending filter update
                    if (SdkData.BackgroundFilterUpdateRequired)
                    {
                        string upToDateHash = LayoutManager.CreateHashOfBeaconId1SInLayout(layoutManager.Layout);

                        if (!string.IsNullOrEmpty(upToDateHash) && SdkData.LayoutBeaconId1Hash.Equals(upToDateHash))
                        {
                            // Background filter updated successfully
                            SdkData.BackgroundFilterUpdateRequired = false;

                            BackgroundFiltersUpdated?.Invoke(this, null);
                        }
                    }
                    else if (string.IsNullOrEmpty(SdkData.LayoutBeaconId1Hash))
                    {
                        // This is the first time the background task is registered with valid layout =>
                        // set the hash
                        string upToDateHash = LayoutManager.CreateHashOfBeaconId1SInLayout(layoutManager.Layout);

                        if (!string.IsNullOrEmpty(upToDateHash))
                        {
                            SdkData.LayoutBeaconId1Hash = upToDateHash;
                        }
                    }
                }
            }

            //Load last events from background
            await LoadBackgroundActions();

            return(result);
        }
        /// <summary>
        /// Register background tasks, by the given configuration.
        /// </summary>
        /// <param name="configuration">Configuration for the new registration.</param>
        public async Task <BackgroundTaskRegistrationResult> RegisterBackgroundTaskAsync(SdkConfiguration configuration)
        {
            BackgroundTaskRegistrationResult result = new BackgroundTaskRegistrationResult()
            {
                Success   = IsBackgroundTaskRegistered,
                Exception = null
            };

            if (!result.Success)
            {
                // Prompt user to accept the request
                BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();

                if (backgroundAccessStatus == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity ||
                    backgroundAccessStatus == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity)
                {
                    result = RegisterTimedBackgroundTask(configuration.BackgroundTimerClassName);

                    if (result.Success)
                    {
                        result = await RegisterAdvertisementWatcherBackgroundTaskAsync(configuration);
                    }
                }

                if (result.Success)
                {
                    Logger.Debug("BackgroundTaskManager.RegisterBackgroundTask(): Registration successful");
                }
            }
            else
            {
                Logger.Debug("BackgroundTaskManager.RegisterBackgroundTask(): Already registered");
            }

            return(result);
        }
 /// <summary>
 /// Renew the registrations of the background taks.
 /// </summary>
 /// <param name="configuration">Configuration for the new registration.</param>
 public async Task <BackgroundTaskRegistrationResult> UpdateBackgroundTaskAsync(SdkConfiguration configuration)
 {
     UnregisterBackgroundTask();
     return(await RegisterBackgroundTaskAsync(configuration));
 }
        /// <summary>
        /// Registers the BLE advertisement watcher background task.
        /// </summary>
        /// <param name="configuration">Configuration for the new registration.</param>
        /// <returns>The registration result.</returns>
        private async Task<BackgroundTaskRegistrationResult> RegisterAdvertisementWatcherBackgroundTaskAsync(SdkConfiguration configuration)
        {
            BackgroundTaskRegistrationResult result = new BackgroundTaskRegistrationResult()
            {
                Success = false,
                Exception = null
            };

            if (BackgroundTaskRegistered(AdvertisementClass))
            {
                // Already registered
                Logger.Debug("BackgroundTaskManager.RegisterAdvertisementWatcherBackgroundTask(): Already registered");
                result.Success = true;
            }
            else
            {
                BackgroundTaskBuilder backgroundTaskBuilder = new BackgroundTaskBuilder();

                backgroundTaskBuilder.Name = AdvertisementClass + Guid.NewGuid();
                backgroundTaskBuilder.TaskEntryPoint = configuration.BackgroundAdvertisementClassName;

                BluetoothLEAdvertisementWatcherTrigger advertisementWatcherTrigger = new BluetoothLEAdvertisementWatcherTrigger();

                // This filter includes all Sensorberg beacons 
                var pattern = BeaconFactory.UuidToAdvertisementBytePattern(configuration.BackgroundBeaconUuidSpace, configuration.ManufacturerId, configuration.BeaconCode);
                advertisementWatcherTrigger.AdvertisementFilter.BytePatterns.Add(pattern);

                ILayoutManager layoutManager = ServiceManager.LayoutManager;

                AppSettings = await ServiceManager.SettingsManager.GetSettings();

                // Using MaxSamplingInterval as SamplingInterval ensures that we get an event only
                // when entering or exiting from the range of the beacon
                advertisementWatcherTrigger.SignalStrengthFilter.SamplingInterval = advertisementWatcherTrigger.MaxSamplingInterval;
                if (AppSettings.RssiEnterThreshold != null && AppSettings.RssiEnterThreshold.Value >= -128 &&
                    AppSettings.RssiEnterThreshold.Value <= 127)
                {
                    advertisementWatcherTrigger.SignalStrengthFilter.InRangeThresholdInDBm = AppSettings.RssiEnterThreshold;
                }
                else
                {
                    advertisementWatcherTrigger.SignalStrengthFilter.InRangeThresholdInDBm = Constants.DefaultBackgroundScannerEnterThreshold;
                }

                advertisementWatcherTrigger.SignalStrengthFilter.OutOfRangeThresholdInDBm = SignalStrengthFilterOutOfRangeThresholdInDBm;
                advertisementWatcherTrigger.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(AppSettings.BeaconExitTimeout);

                IBackgroundTrigger trigger = advertisementWatcherTrigger;

                backgroundTaskBuilder.SetTrigger(trigger);

                try
                {
                    BackgroundTaskRegistration backgroundTaskRegistration = backgroundTaskBuilder.Register();
                    backgroundTaskRegistration.Completed += OnAdvertisementWatcherBackgroundTaskCompleted;
                    backgroundTaskRegistration.Progress += OnAdvertisementWatcherBackgroundTaskProgress;

                    result.Success = true;
                }
                catch (Exception ex)
                {
                    result.Exception = ex;
                    Logger.Error("BackgroundTaskManager.RegisterAdvertisementWatcherBackgroundTask(): Failed to register: ", ex);
                    if (ex.Message.Contains("0x800710DF)"))
                    {
                        await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await new MessageDialog("Activate Bluetooth for the app").ShowAsync());
                    }
                }

                if (result.Success)
                {
                    // Check if there was a pending filter update
                    if (SdkData.BackgroundFilterUpdateRequired)
                    {
                        string upToDateHash = LayoutManager.CreateHashOfBeaconId1SInLayout(layoutManager.Layout);

                        if (!string.IsNullOrEmpty(upToDateHash) && SdkData.LayoutBeaconId1Hash.Equals(upToDateHash))
                        {
                            // Background filter updated successfully
                            SdkData.BackgroundFilterUpdateRequired = false;

                            BackgroundFiltersUpdated?.Invoke(this, null);
                        }
                    }
                    else if (string.IsNullOrEmpty(SdkData.LayoutBeaconId1Hash))
                    {
                        // This is the first time the background task is registered with valid layout =>
                        // set the hash
                        string upToDateHash = LayoutManager.CreateHashOfBeaconId1SInLayout(layoutManager.Layout);

                        if (!string.IsNullOrEmpty(upToDateHash))
                        {
                            SdkData.LayoutBeaconId1Hash = upToDateHash;
                        }
                    }
                }
            }

            //Load last events from background
            await LoadBackgroundActions();

            return result;
        }
        /// <summary>
        /// Register background tasks, by the given configuration.
        /// </summary>
        /// <param name="configuration">Configuration for the new registration.</param>
        public async Task<BackgroundTaskRegistrationResult> RegisterBackgroundTaskAsync(SdkConfiguration configuration)
        {
            BackgroundTaskRegistrationResult result = new BackgroundTaskRegistrationResult()
            {
                Success = IsBackgroundTaskRegistered,
                Exception = null
            };

            if (!result.Success)
            {
                // Prompt user to accept the request
                BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();
                if (backgroundAccessStatus == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity
                    || backgroundAccessStatus == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity)
                {
                    result = RegisterTimedBackgroundTask(configuration.BackgroundTimerClassName);

                    if (result.Success)
                    {
                        result = await RegisterAdvertisementWatcherBackgroundTaskAsync(configuration);
                    }
                }

                if (result.Success)
                {
                    Logger.Debug("BackgroundTaskManager.RegisterBackgroundTask(): Registration successful");
                }
            }
            else
            {
                Logger.Debug("BackgroundTaskManager.RegisterBackgroundTask(): Already registered");
            }

            return result;
        }
 /// <summary>
 /// Renew the registrations of the background taks.
 /// </summary>
 /// <param name="configuration">Configuration for the new registration.</param>
 public async Task<BackgroundTaskRegistrationResult> UpdateBackgroundTaskAsync(SdkConfiguration configuration)
 {
     UnregisterBackgroundTask();
     return await RegisterBackgroundTaskAsync(configuration);
 }
        /// <summary>
        /// Initializes the SDK using the given configuration. The scanner can be used separately, but
        /// the resolving beacon actions cannot be done unless the SDK is initialized.
        /// If background task is enabled, this method check if there are updates for the
        /// background task filters available and updates them if so.
        /// </summary>
        public async Task InitializeAsync(SdkConfiguration configuration)
        {
            Status.IsApiKeyValid = false;
            _logger.Debug("InitializeAsync");
            Configuration = configuration;

            SdkEngine.Configuration = configuration;


            if (!IsInitialized)
            {
                await SdkEngine.InitializeAsync();
                await InitializeSettingsAsync();
                Status.IsApiKeyValid = ServiceManager.LayoutManager.IsLayoutValid;
                Scanner.StatusChanged += OnScannerStatusChanged;
                Scanner.BeaconEvent += OnBeaconEventAsync;
            }

            if (SdkData.BackgroundTaskEnabled)
            {
                _logger.Debug("InitializeAsync#InitializeBackgground");
                await UpdateBackgroundTaskIfNeededAsync();
            }

            if (configuration.AutoStartScanner)
            {
                StartScanner();
            }
        }