public void FetchSteps(Action <double> completionHandler)
        {
            var calendar          = NSCalendar.CurrentCalendar;
            var startDate         = DateTime.Today;
            var endDate           = DateTime.Now;
            var stepsQuantityType = HKQuantityType.Create(HKQuantityTypeIdentifier.StepCount);

            var predicate = HKQuery.GetPredicateForSamples((NSDate)startDate, (NSDate)endDate, HKQueryOptions.StrictStartDate);

            var query = new HKStatisticsQuery(stepsQuantityType, predicate, HKStatisticsOptions.CumulativeSum,
                                              (HKStatisticsQuery resultQuery, HKStatistics results, NSError error) =>
            {
                if (error != null && completionHandler != null)
                {
                    completionHandler(0.0f);
                }

                var totalSteps = results.SumQuantity();
                if (totalSteps == null)
                {
                    totalSteps = HKQuantity.FromQuantity(HKUnit.Count, 0.0);
                }

                completionHandler(totalSteps.GetDoubleValue(HKUnit.Count));
            });

            HealthStore.ExecuteQuery(query);
        }
        void UpdateJournal(object sender, EventArgs args)
        {
            var calendar = NSCalendar.CurrentCalendar;

            var startDate = DateTime.Now.Date;
            var endDate   = startDate.AddDays(1);

            var sampleType = HKSampleType.GetQuantityType(HKQuantityTypeIdentifierKey.DietaryEnergyConsumed);
            var predicate  = HKQuery.GetPredicateForSamples((NSDate)startDate, (NSDate)endDate, HKQueryOptions.None);

            var query = new HKSampleQuery(sampleType, predicate, 0, new NSSortDescriptor[0], (resultQuery, results, error) => {
                if (error != null)
                {
                    Console.WriteLine("An error occured fetching the user's tracked food. " +
                                      "In your app, try to handle this gracefully. The error was: {0}.", error.LocalizedDescription);
                    return;
                }

                InvokeOnMainThread(() => {
                    FoodItems.RemoveAllObjects();
                    foreach (HKQuantitySample sample in results)
                    {
                        var foodName  = (NSString)sample.Metadata.Dictionary [HKMetadataKey.FoodType];
                        double joules = sample.Quantity.GetDoubleValue(HKUnit.Joule);
                        var foodItem  = FoodItem.Create(foodName, joules);

                        FoodItems.Add(foodItem);
                    }

                    TableView.ReloadData();
                });
            });

            HealthStore.ExecuteQuery(query);
        }
        public void FetchMetersWalked(Action <double> completionHandler)
        {
            var calendar          = NSCalendar.CurrentCalendar;
            var startDate         = DateTime.Today;
            var endDate           = DateTime.Now;
            var stepsQuantityType = HKQuantityType.Create(HKQuantityTypeIdentifier.DistanceWalkingRunning);

            var predicate = HKQuery.GetPredicateForSamples((NSDate)startDate, (NSDate)endDate, HKQueryOptions.StrictStartDate);

            var query = new HKStatisticsQuery(stepsQuantityType, predicate, HKStatisticsOptions.CumulativeSum,
                                              (HKStatisticsQuery resultQuery, HKStatistics results, NSError error) =>
            {
                if (error != null && completionHandler != null)
                {
                    completionHandler(0);
                }

                var distance = results.SumQuantity();
                if (distance == null)
                {
                    distance = HKQuantity.FromQuantity(HKUnit.Meter, 0);
                }

                completionHandler(distance.GetDoubleValue(HKUnit.Meter));
            });

            HealthStore.ExecuteQuery(query);
        }
        void FetchMostRecentData(Action <double, NSError> completionHandler)
        {
            var calendar  = NSCalendar.CurrentCalendar;
            var startDate = DateTime.Now.Date;
            var endDate   = startDate.AddDays(1);

            var sampleType = HKQuantityType.GetQuantityType(HKQuantityTypeIdentifierKey.DietaryEnergyConsumed);
            var predicate  = HKQuery.GetPredicateForSamples((NSDate)startDate, (NSDate)endDate, HKQueryOptions.StrictStartDate);

            var query = new HKStatisticsQuery(sampleType, predicate, HKStatisticsOptions.CumulativeSum,
                                              (HKStatisticsQuery resultQuery, HKStatistics results, NSError error) => {
                if (error != null && completionHandler != null)
                {
                    completionHandler(0.0f, error);
                }

                var totalCalories = results.SumQuantity();
                if (totalCalories == null)
                {
                    totalCalories = HKQuantity.FromQuantity(HKUnit.Joule, 0.0);
                }

                if (completionHandler != null)
                {
                    completionHandler(totalCalories.GetDoubleValue(HKUnit.Joule), error);
                }
            });

            HealthStore.ExecuteQuery(query);
        }
        void FetchMostRecentData(HKQuantityType quantityType, Action <HKQuantity, NSError> completion)
        {
            var timeSortDescriptor = new NSSortDescriptor(HKSample.SortIdentifierEndDate, false);
            var query = new HKSampleQuery(quantityType, null, 1, new NSSortDescriptor[] { timeSortDescriptor },
                                          (HKSampleQuery resultQuery, HKSample[] results, NSError error) => {
                if (completion != null && error != null)
                {
                    completion(null, error);
                    return;
                }

                HKQuantity quantity = null;
                if (results.Length != 0)
                {
                    var quantitySample = (HKQuantitySample)results [results.Length - 1];
                    quantity           = quantitySample.Quantity;
                }

                if (completion != null)
                {
                    completion(quantity, error);
                }
            });

            HealthStore.ExecuteQuery(query);
        }
        protected override Task <List <Datum> > PollAsync(CancellationToken cancellationToken)
        {
            List <Datum> data = new List <Datum>();

            ManualResetEvent queryWait = new ManualResetEvent(false);
            Exception        exception = null;

            HealthStore.ExecuteQuery(new HKAnchoredObjectQuery(ObjectType as HKSampleType, null, (nuint)_queryAnchor, nuint.MaxValue, new HKAnchoredObjectResultHandler2(

                                                                   (query, samples, newQueryAnchor, error) =>
            {
                try
                {
                    if (error == null)
                    {
                        foreach (HKSample sample in samples)
                        {
                            Datum datum = ConvertSampleToDatum(sample);
                            if (datum != null)
                            {
                                data.Add(datum);
                            }
                        }

                        _queryAnchor = (int)newQueryAnchor;
                    }
                    else
                    {
                        throw new Exception("Error while querying HealthKit for " + ObjectType + ":  " + error.Description);
                    }
                }
                catch (Exception ex)
                {
                    exception = new Exception("Failed storing HealthKit samples:  " + ex.Message);
                }
                finally
                {
                    queryWait.Set();
                }
            })));

            queryWait.WaitOne();

            if (exception != null)
            {
                throw exception;
            }

            // let the system know that we polled but didn't get any data
            if (data.Count == 0)
            {
                data.Add(null);
            }

            return(Task.FromResult(data));
        }
        protected override IEnumerable <Datum> Poll(CancellationToken cancellationToken)
        {
            List <Datum> data = new List <Datum>();

            ManualResetEvent queryWait = new ManualResetEvent(false);
            Exception        exception = null;

            HealthStore.ExecuteQuery(new HKAnchoredObjectQuery(ObjectType as HKSampleType, null, (nuint)_queryAnchor, nuint.MaxValue, new HKAnchoredObjectResultHandler2(
                                                                   (query, samples, newQueryAnchor, error) =>
            {
                try
                {
                    if (error == null)
                    {
                        foreach (HKSample sample in samples)
                        {
                            Datum datum = ConvertSampleToDatum(sample);
                            if (datum != null)
                            {
                                data.Add(datum);
                            }
                        }

                        _queryAnchor = (int)newQueryAnchor;
                    }
                    else
                    {
                        throw new Exception("Error while querying HealthKit for " + ObjectType + ":  " + error.Description);
                    }
                }
                catch (Exception ex)
                {
                    exception = new Exception("Failed storing HealthKit samples:  " + ex.Message);
                }
                finally
                {
                    queryWait.Set();
                }
            })));

            queryWait.WaitOne();

            if (exception != null)
            {
                throw exception;
            }

            if (data.Count == 0)
            {
                throw new Exception("User has not provided -- or has not allowed access to -- any " + ObjectType + " information since last poll.");
            }

            return(data);
        }
        void RefreshQuantityValue(NSString quantityTypeKey, HKQuantityType quantityType)
        {
            NSSortDescriptor timeSortDescriptor = new NSSortDescriptor(HKSample.SortIdentifierEndDate, false);

            // Since we are interested in retrieving the user's latest sample, we sort the samples in descending order, and set the limit to 1. We are not filtering the data, and so the predicate is set to nil.
            HKSampleQuery query = new HKSampleQuery(quantityType, null, 100, new NSSortDescriptor[] { timeSortDescriptor },
                                                    new HKSampleQueryResultsHandler(new Action <HKSampleQuery, HKSample[], NSError>((query2, results, error) =>
            {
                if (results != null && results.Length > 0)
                {
                    if (quantityTypeKey == HKQuantityTypeIdentifierKey.Height)
                    {
                        //We have height, process the last entry into inches.
                        var quantitySample = results.LastOrDefault() as HKQuantitySample;

                        var quantity = quantitySample.Quantity;

                        var heightUnit = HKUnit.Inch;

                        DispatchQueue.MainQueue.DispatchAsync(() => {
                            var dataStore = StateDispatcher <HealthState> .State;

                            HealthStateMutator.MutateHeight(dataStore,
                                                            () => quantity.GetDoubleValue(heightUnit));

                            StateDispatcher <HealthState> .Refresh();
                        });
                    }
                    else if (quantityTypeKey == HKQuantityTypeIdentifierKey.StepCount)
                    {
                        DispatchQueue.MainQueue.DispatchAsync(() => {
                            //Now we need to deliver all the blood glucose entries in a list to any listeners.
                            var entries = new List <StepCountEntry>();

                            //Now also deliver all blood glucose readings up to the UI via the 'diff engine' for easy UITableViewController based updating.
                            foreach (var entry in results)
                            {
                                var sample = entry as HKQuantitySample;
                                if (sample != null)
                                {
                                    entries.Add(new HealthKitStepCountEntry(sample));
                                }
                            }

                            HealthStateDispatchers.StepCountListStateDispatcher.Refresh(
                                entries.Cast <StepCountEntry>().ToList());
                        });
                    }
                    else if (quantityTypeKey == HKQuantityTypeIdentifierKey.BloodGlucose)
                    {
                        DispatchQueue.MainQueue.DispatchAsync(() => {
                            //Refresh the views with the last known blood glucose quantity via HealthState and BloodGlucoseRecommendationState.
                            var lastBloodGlucoseQuantity = (results.LastOrDefault() as HKQuantitySample).Quantity;

                            var healthState = StateDispatcher <HealthState> .State;

                            var mgPerDL = HKUnit.FromString("mg/dL");
                            HealthStateMutator.MutateBloodGlucose(healthState,
                                                                  () => lastBloodGlucoseQuantity.GetDoubleValue(mgPerDL));


                            //At this point all UI subscribers to the HealthState object will update.
                            StateDispatcher <HealthState> .Refresh();



                            var recommendationStore = StateDispatcher <BloodGlucoseRecommendationState> .State;

                            BloodGlucoseRecommendationMutator.MutateBloodGlucose(
                                recommendationStore, () => healthState.BloodGlucose);

                            //At this point all UI subscribers to the BloodGlucoseRecommendationState will update.
                            StateDispatcher <BloodGlucoseRecommendationState> .Refresh();



                            //Now we need to deliver all the blood glucose entries in a list to any listeners.
                            var newBloodGlucoseEntries = new List <HealthKitBloodGlucoseEntry>();

                            //Now also deliver all blood glucose readings up to the UI via the 'diff engine' for easy UITableViewController based updating.
                            foreach (var bloodGlucoseEntry in results)
                            {
                                var bloodGlucoseSample = bloodGlucoseEntry as HKQuantitySample;
                                if (bloodGlucoseSample != null)
                                {
                                    newBloodGlucoseEntries.Add(new HealthKitBloodGlucoseEntry(bloodGlucoseSample));
                                }
                            }

                            HealthStateDispatchers.BloodGlucoseListStateDispatcher.Refresh(
                                newBloodGlucoseEntries.Cast <BloodGlucoseEntry>().ToList());
                        });
                    }
                }
            })));

            HealthStore.ExecuteQuery(query);
        }
        public void BeginWorkout(DateTime beginDate)
        {
            // Obtain the `HKObjectType` for active energy burned and the `HKUnit` for kilocalories.
            var activeEnergyType = HKQuantityType.Create(HKQuantityTypeIdentifier.ActiveEnergyBurned);

            if (activeEnergyType == null)
            {
                return;
            }

            var energyUnit = HKUnit.Kilocalorie;

            // Update properties.
            WorkoutBeginDate = beginDate;
            workoutButton.SetTitle("End Workout");

            // Set up a predicate to obtain only samples from the local device starting from `beginDate`.

            var datePredicate = HKQuery.GetPredicateForSamples((NSDate)beginDate, null, HKQueryOptions.None);

            var devices         = new NSSet <HKDevice> (new HKDevice[] { HKDevice.LocalDevice });
            var devicePredicate = HKQuery.GetPredicateForObjectsFromDevices(devices);
            var predicate       = NSCompoundPredicate.CreateAndPredicate(new NSPredicate[] { datePredicate, devicePredicate });

            //Create a results handler to recreate the samples generated by a query of active energy samples so that they can be associated with this app in the move graph.It should be noted that if your app has different heuristics for active energy burned you can generate your own quantities rather than rely on those from the watch.The sum of your sample's quantity values should equal the energy burned value provided for the workout
            Action <List <HKSample> > sampleHandler;

            sampleHandler = (List <HKSample> samples) => {
                DispatchQueue.MainQueue.DispatchAsync(delegate {
                    var accumulatedSamples = new List <HKQuantitySample> ();

                    var initialActivityEnergy = CurrentActiveEnergyQuantity.GetDoubleValue(energyUnit);
                    double accumulatedValue   = initialActivityEnergy;
                    foreach (HKQuantitySample sample in samples)
                    {
                        accumulatedValue = accumulatedValue + sample.Quantity.GetDoubleValue(energyUnit);
                        var ourSample    = HKQuantitySample.FromType(activeEnergyType, sample.Quantity, sample.StartDate, sample.EndDate);
                        accumulatedSamples.Add(ourSample);
                    }

                    // Update the UI.
                    CurrentActiveEnergyQuantity = HKQuantity.FromQuantity(energyUnit, accumulatedValue);
                    activeEnergyBurnedLabel.SetText($"{accumulatedValue}");

                    // Update our samples.
                    ActiveEnergySamples.AddRange(accumulatedSamples);
                });
            };

            // Create a query to report new Active Energy Burned samples to our app.
            var activeEnergyQuery = new HKAnchoredObjectQuery(activeEnergyType, predicate, null, HKSampleQuery.NoLimit, (query, addedObjects, deletedObjects, newAnchor, error) => {
                if (error == null)
                {
                    // NOTE: `deletedObjects` are not considered in the handler as there is no way to delete samples from the watch during a workout
                    ActiveEnergySamples = new List <HKSample>(addedObjects);
                    sampleHandler(ActiveEnergySamples);
                }
                else
                {
                    Console.WriteLine($"An error occured executing the query. In your app, try to handle this gracefully. The error was: {error}.");
                }
            });

            // Assign the same handler to process future samples generated while the query is still active.
            activeEnergyQuery.UpdateHandler = (query, addedObjects, deletedObjects, newAnchor, error) => {
                if (error == null)
                {
                    ActiveEnergySamples = new List <HKSample> (addedObjects);
                    sampleHandler(ActiveEnergySamples);
                }
                else
                {
                    Console.WriteLine($"An error occured executing the query. In your app, try to handle this gracefully. The error was: {error}.");
                }
            };

            // Start Query
            CurrentQuery = activeEnergyQuery;
            HealthStore.ExecuteQuery(activeEnergyQuery);
        }