Essential practices
After you have learned how to configure the development environment and built apps using the SensorCore SDK, there are still a few more things that you should know. There are some general patterns and practices about how you should use SensorCore to ensure stability and compatibility. Please note that the same essential patterns and practices are used in the samples in an identical way, although they are only documented in detail in here. In this section, we will review initializing, error handling, and application lifecycle management.
Calling the SensorCore SDK safely
In order to call SensorCore APIs safely, you need to handle exceptions properly. The APIs throw exceptions if SensorCore is not supported by the device, or if required settings are not enabled.
We have provided a wrapper for you to use when calling SensorCore APIs that will take care of these things for you.
/// <summary> /// Calls given function and handles any SensorCore exceptions. /// </summary> /// <param name="action">Function to call</param> /// <returns><c>true</c> if the call was successful, <c>false</c> otherwise</returns> private async Task<bool> CallSensorcoreApiAsync( Func<Task> action ) { Exception failure = null; try { await action(); } catch( Exception e ) { failure = e; } if( failure != null ) { MessageDialog dialog; switch( SenseHelper.GetSenseError( failure.HResult ) ) { case SenseError.LocationDisabled: { dialog = new MessageDialog( "Location has been disabled. Do you want to open Location settings now?", "Information" ); dialog.Commands.Add( new UICommand( "Yes", async cmd => await SenseHelper.LaunchLocationSettingsAsync() ) ); dialog.Commands.Add( new UICommand( "No" ) ); await dialog.ShowAsync(); new System.Threading.ManualResetEvent( false ).WaitOne( 500 ); return false; } case SenseError.SenseDisabled: { dialog = new MessageDialog( "Places visited has been disabled. Do you want to open Motion data settings now?", "Information" ); dialog.Commands.Add( new UICommand( "Yes", new UICommandInvokedHandler( async ( cmd ) => await SenseHelper.LaunchSenseSettingsAsync() ) ) ); dialog.Commands.Add( new UICommand( "No" ) ); await dialog.ShowAsync(); new System.Threading.ManualResetEvent( false ).WaitOne( 500 ); return false; } default: { dialog = new MessageDialog( "Failure: " + SenseHelper.GetSenseError( failure.HResult ), "" ); await dialog.ShowAsync(); return false; } } } return true; }
Initializing SensorCore
To make it easier to switch between the actual hardware class and the simulator, you can use an alias for the class:
using Monitor = Lumia.Sense.PlaceMonitor;
In order to use the sensors, you need to instantiate them first with the GetDefaultAsync() method. You can call the initialization using the wrapper provided above like this:
await CallSensorcoreApiAsync( async () => { placeMonitor = await Monitor.GetDefaultAsync(); } );
Sensor activation and deactivation
When an application is put to the background, sensors need to be deactivated, and when an application is brought to the foreground, sensors need to be activated again. In a Universal application, you should handle this with a VisibilityChanged event:
Window.Current.VisibilityChanged += async( oo, ee ) => { if( !ee.Visible ) { await CallSensorcoreApiAsync( async () => { if( _sensor != null ) { await _sensor.DeactivateAsync(); } } ); } else { await CallSensorcoreApiAsync( async () => { if( _sensor != null ) { await _sensor.ActivateAsync(); } else { _sensor = await StepCounter.GetDefaultAsync(); } } ); } }
In a Silverlight application, you would do the same like this:
protected async override void OnNavigatedTo( NavigationEventArgs e ) { if( _stepCounter == null ) { await Initialize(); } await _stepCounter.ActivateAsync(); } protected override async void OnNavigatingFrom( NavigatingCancelEventArgs e ) { await _stepCounter.DeactivateAsync(); }
Verifying hardware support
It is important to understand that the SensorCore SDK relies on hardware that is not present on all phones. For that reason, the first thing you should do is to check if the device supports the feature of the SensorCore SDK that you are using. Lumia devices prior to WP 8.1 and Cyan SW update do not support SensorCore.
You can check if a sensor is supported by the device by using the IsSupportedAsync() method. Please note that the call to IsSupportedAsync() may throw an exception if the user has turned off location services or disabled location access to the application. Therefore, you should use the wrapper function to handle any exceptions.
await CallSensorcoreApiAsync( async () => { if( !await StepCounter.IsSupportedAsync() ) { // Show error message or hide UI controls... } } );
To check for specific feature availability, you can use SenseHelper.GetSupportedApiSetAsync(). API documentation, which specifies which API set is required for each feature. For example, querying place history in Place Monitor requires API set 4 or greater. Details about API sets are available in the application migration chapter.
await CallSensorcoreApiAsync( async () => { uint apiSet = await SenseHelper.GetSupportedApiSetAsync(); if( apiSet >= 4 ) { // New Place monitor APIs are supported by this device. var history = await _placeMonitor.GetPlaceHistoryAsync( DateTime.Now.Date, DateTime.Now - DateTime.Now.Date ); } } );
In earlier versions of the SensorCore SDK, SenseHelper.GetSupportedCapabilitiesAsync() was used to check for feature availability. That API has now been deprecated and is being replaced by SenseHelper.GetSupportedApiSetAsync(). This change was done to make it easier to check for feature group availability instead of having to check each feature one by one.
How apps should deal with Motion data settings
If your application depends on the biking activity class, you need to make sure that system location is enabled as well Motion data settings Detailed data collection and Places visited. Also, for more accurate and detailed MovingInVehicle recognition, you need to enable the same settings.
await CallSensorcoreApiAsync( async () => { uint apiSet = await SenseHelper.GetSupportedApiSetAsync(); if( apiSet < 3 ) { MessageDialog dlg = new MessageDialog( "Unfortunately this device does not support biking detection" ); await dlg.ShowAsync(); } else { MotionDataSettings settings = await SenseHelper.GetSettingsAsync(); if( settings.DataQuality == DataCollectionQuality.Basic ) { MessageDialog dlg = new MessageDialog( "In order to recognize biking you need to enable detailed data collection in motion data settings. Do you want to open settings now?", "Information" ); dlg.Commands.Add( new UICommand( "Yes", new UICommandInvokedHandler( async ( cmd ) => await SenseHelper.LaunchSenseSettingsAsync() ) ) ); dlg.Commands.Add( new UICommand( "No" ) ); await dlg.ShowAsync(); } } } );
In order to access location based sensors (Place monitor, TrackPoint monitor), the user needs to enable system location and Places visited in Motion data settings.
await CallSensorcoreApiAsync( async () => { uint apiSet = await SenseHelper.GetSupportedApiSetAsync(); MotionDataSettings settings = await SenseHelper.GetSettingsAsync(); if( !settings.PlacesVisited ) { MessageDialog dlg = new MessageDialog( "In order to see your running and walking routes you need to enable Places visited in motion data settings. Do you want to open settings now?", "Information" ); dlg.Commands.Add( new UICommand( "Yes", new UICommandInvokedHandler( async ( cmd ) => await SenseHelper.LaunchSenseSettingsAsync() ) ) ); dlg.Commands.Add( new UICommand( "No" ) ); await dlg.ShowAsync(); } else if( apiSet >= 3 && settings.DataQuality == DataCollectionQuality.Basic ) { MessageDialog dlg = new MessageDialog( "In order to get better quality running and walking routes you should enable detailed data collection in motion data settings. Do you want to open settings now?", "Helpful tip"); dlg.Commands.Add( new UICommand( "Yes", new UICommandInvokedHandler( async ( cmd ) => await SenseHelper.LaunchSenseSettingsAsync() ) ) ); dlg.Commands.Add( new UICommand( "No" ) ); await dlg.ShowAsync(); } } );
Error handling
Lumia SensorCore SDK APIs return errors by throwing exceptions. You can get more detailed information about the exception by using SenseHelper.GetSenseError().
Apps that utilize the SensorCore SDK can also be installed on devices that do not support SensorCore SDK features. An app should prepare for a case where no sensor or sensor data is available. If an app has no function without the SensorCore SDK, it should be stated clearly in the Store description.
One of the most important error situations is when a method fails because the user has disabled either location services or motion data collection. You should provide the user with an easy way of going to system settings to enable the necessary feature or features. You can, for example, encapsulate the API calls with the CallSensorcoreApiAsync() we defined earlier in the Getting started section to handle any errors.
You can then use that method to wrap all SensorCore SDK related calls:
if( await CallSensorcoreApiAsync( async() => { _stepCounter = await StepCounter.GetDefaultAsync(); } ) ) { // Success } else { // Failure }