Migrating apps from using SensorCore APIs to using Win10 APIs

If you have apps that use Lumia SensorCore Step Counter or Activity Monitor APIs, we recommend that you upgrade the apps to use the corresponding Win10 APIs. For more information about the Win10 APIs, review the following topics:

Unfortunately, Place Monitor and Track Point Monitor do not have equivalent Win10 APIs available and thus apps that use those APIs cannot be migrated. Legacy devices will still continue to support these APIs for some time, but you should start removing them from your apps.

As support for Win10 APIs will be limited at first, you may want to consider supporting both SensorCore and platform APIs at the same time until more devices that support Win10 APIs become available.

The following chapter explains the differences between Lumia.Sense.StepCounter and Windows.Devices.Sensors.Pedometer and provides helper methods to ease the migration.

Migrating from Lumia.Sense.StepCounter to Windows.Devices.Sensors.Pedometer

There are quite a few differences between Lumia.SenseStepCounter and Windows.Devices.Sensors.Pedometer. Win10 APIs may store history data at much higher frequency (e.g. at one minute intervals) depending on the device capabilities. Also, history items are not synced with system clock minute boundary and there are separate history items for walking and running steps. In addition, the Win10 API does not provide the GetStepCountForRangeAsync() method.

You can use the following code to implement GetStepCountForRangeAsync() using Win10 API.

#region Container for step counts and durations
/// <summary>
/// The container for walking and running step count and duration.
/// </summary>
public sealed class StepCount
{
    /// <summary>
    /// Walking steps count
    /// </summary>
    public uint WalkingStepCount { get; set; }
    /// <summary>
    /// Walking time
    /// </summary>
    public TimeSpan WalkTime { get; set; }
    /// <summary>
    /// Running steps count
    /// </summary>
    public uint RunningStepCount { get; set; }
    /// <summary>
    /// Running time
    /// </summary>
    public TimeSpan RunTime { get; set; }

    /// <summary>
    /// Constructor
    /// </summary>
    public StepCount() { }
}
#endregion

/// <summary>
/// Returns walking and running step count and duration for the given time period.
/// </summary>
/// <param name="timestamp">Start time</param>
/// <param name="span">Duration</param>
/// <returns>Walking and running step count and duration for the given time
/// period.</returns>
public static async Task<StepCount> GetStepCountForRangeAsync(
    DateTimeOffset timestamp,
    TimeSpan span )
{
    if( span.TotalMilliseconds < Pedometer.MinimumReportInterval ) throw new Exception( "Too small timespan specified, minimum time span is " + Pedometer.MinimumReportInterval + " milliseconds." );
    StepCount finalReading = new StepCount();
    // Overshoot by twice the minimum report interval in order to get the previous
    // and next history item outside the given time period. This logic assumes that
    // data is stored in history with the minimum report interval.
    TimeSpan overshoot = TimeSpan.FromMilliseconds( Pedometer.MinimumReportInterval * 2 );
    IReadOnlyList<PedometerReading> history = await Pedometer.GetSystemHistoryAsync(
        timestamp - overshoot,
        span + overshoot + overshoot );

    PedometerReading firstItem = FindClosestStartBoundaryItem(
        history,
        timestamp, PedometerStepKind.Walking );
    PedometerReading lastItem = FindClosestEndBoundaryItem(
        history,
        timestamp + span,
        PedometerStepKind.Walking );
    if( firstItem != null &&
        lastItem != null )
    {
        finalReading.WalkingStepCount = lastItem.CumulativeSteps - firstItem.CumulativeSteps;
        finalReading.WalkTime = lastItem.CumulativeStepsDuration - firstItem.CumulativeStepsDuration;
    }

    firstItem = FindClosestStartBoundaryItem(
        history,
        timestamp, PedometerStepKind.Running );
    lastItem = FindClosestEndBoundaryItem(
        history,
        timestamp + span,
        PedometerStepKind.Running );
    if( firstItem != null &&
        lastItem != null )
    {
        finalReading.RunningStepCount = lastItem.CumulativeSteps - firstItem.CumulativeSteps;
        finalReading.RunTime = lastItem.CumulativeStepsDuration - firstItem.CumulativeStepsDuration;
    }
    return finalReading;
}

/// <summary>
/// Finds the closest item from the history whose timestamp is at the end boundary.
/// </summary>
/// <param name="history">Pedometer reading history to search from</param>
/// <param name="rangeEnd">Search range end boundary</param>
/// <param name="kind">Step kind</param>
/// <returns>First item from the history whose timestamp is closest to the end
/// boundary or <c>null</c> if no such item is found.</returns>
internal static PedometerReading FindClosestEndBoundaryItem(
    IReadOnlyList<PedometerReading> history,
    DateTimeOffset rangeEnd,
    PedometerStepKind kind )
{
    if( history.Count > 1 )
    {
        PedometerReading prevItem = null;
        for( int i = history.Count - 1; i >= 0; i-- )
        {
            PedometerReading item = history[ i ];
            if( item.StepKind == kind &&
                item.CumulativeSteps != 0 )
            {
                if( item.Timestamp < rangeEnd )
                {
                    return ( prevItem != null && ( prevItem.Timestamp - rangeEnd ) < ( rangeEnd - item.Timestamp ) ) ? prevItem : item;
                }
                prevItem = item;
            }
        }
    }
    return null;
}

/// <summary>
/// Finds closest item from the history whose timestamp is at the start boundary.
/// </summary>
/// <param name="history">Pedometer reading history to search from</param>
/// <param name="startTime">Search range start boundary</param>
/// <param name="kind">Step kind</param>
/// <returns>First item from the history whose timestamp is closest to the start
/// boundary or <c>null</c> if no such item is found.</returns>
internal static PedometerReading FindClosestStartBoundaryItem(
    IReadOnlyList<PedometerReading> history,
    DateTimeOffset startTime,
    PedometerStepKind kind )
{
    if( history.Count > 1 )
    {
        PedometerReading prevItem = null;
        for( int i = 0; i < history.Count; i++ )
        {
            PedometerReading item = history[ i ];
            if( item.StepKind == kind &&
                item.CumulativeSteps != 0 )
            {
                if( item.Timestamp > startTime )
                {
                    return ( prevItem != null && ( startTime - prevItem.Timestamp ) < ( item.Timestamp - startTime ) ) ? prevItem : item;
                }
                prevItem = item;
            }
        }
    }
    return null;
}

Migrating from Lumia.Sense.ActivityMonitor to Windows.Devices.Sensors.ActivitySensor

In terms of returned data, there are no major differences between Lumia.Sense.ActivityMonitor and Windows.Devices.Sensors.ActivitySensor. Windows.Devices.Sensors.ActivitySensor includes one more activity type (Fidgeting) and confidence value compared to Lumia.Sense.ActivityMonitor. The Win10 API is, however, missing the GetActivityAtAsync() method and the GetSystemHistoryAsync() method does not include the previous history item, i.e. the activity at the start of the given time period.

You can use the following method to implement GetActivityAtAsync() using Win10 API.

/// <summary>
/// Returns the activity at the given time
/// </summary>
/// <param name="timestamp">Time stamp</param>
/// <returns>Activity at the given time or <c>null</c> if no activity
/// is found.</returns>
public static async Task<ActivitySensorReading> GetActivityAtAsync( DateTimeOffset timestamp )
{
    // We assume here that one day overshoot is enough to cover most cases.
    // If the previous activity lasted longer than that, we will miss it.
    // Overshoot duration can be extended but will decrease performance.
    TimeSpan overshoot = TimeSpan.FromDays( 1 );
    IReadOnlyList<ActivitySensorReading> history = await ActivitySensor.GetSystemHistoryAsync(
        timestamp - overshoot,
        overshoot );
    if( history.Count > 0 )
    {
        return history.Last();
    }
    else
    {
        return null;
    }
}

The following method implements GetActivityHistoryAsync() using the Win10 API.

/// <summary>
/// Returns activity sensor history for the given time period.
/// </summary>
/// <remarks>This method differs from the <c>ActivitySensor.GetSystemHistoryAsync()</c>
/// in that it also returns the activity at the start of the given time period. For
/// example, if you ask for activities for today and the device was idle from
/// 23:00 yesterday until 08:00 this morning, you would miss that activity with
/// <c>ActivitySensor.GetSystemHistoryAsync()</c>, whereas
/// you would get that activity as well using this method.</remarks>
/// <param name="timestamp">Start time</param>
/// <param name="span">Duration</param>
/// <returns>Activity history for the given time period.</returns>
private static async Task<IReadOnlyList<ActivitySensorReading>> GetActivityHistoryAsync(
    DateTimeOffset timestamp,
    TimeSpan span )
{
    IReadOnlyList<ActivitySensorReading> history = await ActivitySensor.GetSystemHistoryAsync(
        timestamp,
        span );
    if( history.Count > 0 &&
        history[ 0 ].Timestamp > timestamp )
    {
        // We assume here that one day overshoot is enough to cover most cases.
        // If the previous activity lasted longer than that, we will miss it.
        // Overshoot duration can be extended but will decrease performance.
        TimeSpan overshoot = TimeSpan.FromDays( 1 );
        IReadOnlyList<ActivitySensorReading> overshootHistory = await ActivitySensor.GetSystemHistoryAsync(
            timestamp - overshoot,
            overshoot );
        if( overshootHistory.Count > 0 )
        {
            List<ActivitySensorReading> finalHistory = new List<ActivitySensorReading>( history );
            finalHistory.Insert( 0, overshootHistory.Last() );
            return finalHistory;
        }
    }
    return history;
}
Show: