Task CreateUpdateTask()
        {
            try
            {
                return(TaskUtils.RunForever(c =>
                {
                    Api
                    .Call <Api.Responses.Processes>(new Api.Requests.Processes(), Canceller.Token)
                    .ContinueWith(t =>
                    {
                        if (t.IsCanceled)
                        {
                            return new TwoLineListItem[0];
                        }

                        if (t.IsFaulted)
                        {
                            throw t.Exception;
                        }

                        return t.Result.processes
                        .Select(p => new TwoLineListItem
                        {
                            Line1 = $"{p.imageName} ({p.pid})",
                            Line2 = $"Memory: {UIConversion.FromBytes(p.memUsage)}, CPU: {TimeSpan.FromMilliseconds(p.cpuTime)}",
                            Tag = p
                        })
                        .OrderBy(i => i.Line1)
                        .ToArray();
                    })
                    .ContinueWith(t =>
                    {
                        RunOnUiThread(() =>
                        {
                            if (t.IsFaulted)
                            {
                                Log.Error(TAG, $"Failed to fetch processes with error {t.Exception.Flatten().InnerException}.");
                                Toast.MakeText(this, $"Failed to fetch processes.", ToastLength.Short).Show();
                                return;
                            }

                            Populate(t.Result);
                        });
                    });
                },
                                            Canceller.Token,
                                            REFRESH_PERIOD));
            }
            catch (Exception e)
            {
                Toast.MakeText(this, $"Failed to connect to {Title}", ToastLength.Short).Show();
                Log.Error(TAG, $"Failed to start activity with error {e}.");
                Finish();
                return(null);
            }
        }
 protected override TwoLineListItem[] Transform(Api.Responses.Service model)
 {
     return(new TwoLineListItem[]
     {
         new TwoLineListItem {
             Line1 = "Version", Line2 = model.version
         },
         new TwoLineListItem {
             Line1 = "Runtime", Line2 = string.Join(System.Environment.NewLine, model.versions.Select(m => $"{m.Name}@{m.Version}"))
         },
         new TwoLineListItem {
             Line1 = "Resident Set Size", Line2 = UIConversion.FromBytes(model.memory.residentSetSize)
         },
         new TwoLineListItem {
             Line1 = "Heap Used", Line2 = UIConversion.FromBytes(model.memory.heapUsed)
         },
         new TwoLineListItem {
             Line1 = "Heap Total", Line2 = UIConversion.FromBytes(model.memory.heapTotal)
         },
     });
 }
 protected override TwoLineListItem[] Transform(Api.Responses.Os model)
 {
     return(new TwoLineListItem[]
     {
         new TwoLineListItem {
             Line1 = "Uptime", Line2 = model.uptime
         },
         new TwoLineListItem {
             Line1 = "Architecture", Line2 = model.arch
         },
         new TwoLineListItem {
             Line1 = "Cpu(s)", Line2 = string.Join(System.Environment.NewLine, model.cpus.Select(cpu => cpu.model).GroupBy(s => s).Select(g => $"{g.Count()} x {g.First()}"))
         },
         new TwoLineListItem {
             Line1 = "Free Memory", Line2 = UIConversion.FromBytes(model.freemem)
         },
         new TwoLineListItem {
             Line1 = "Used Memory", Line2 = UIConversion.FromBytes(model.usedmem)
         },
         new TwoLineListItem {
             Line1 = "Total Memory", Line2 = UIConversion.FromBytes(model.totalmem)
         },
     });
 }
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            Name            = Intent.Extras.GetString("name");
            Address         = Intent.Extras.GetString("address");
            DatasetName     = Intent.Extras.GetString("datasetName");
            DatasetAlias    = Intent.Extras.GetString("datasetAlias");
            TimestampOffset = Intent.Extras.GetLong("timestampOffset");
            var sourceUnit = Intent.Extras.GetString("datasetSourceUnit");
            var targetUnit = Intent.Extras.GetString("datasetTargetUnit");

            Title = $"{Name} ({Address})";

            try
            {
                Converter = UnitConverter.Create(sourceUnit, targetUnit);

                Api = new ApiClient(Address);

                Api.Call <Api.Responses.Dataset>(new Api.Requests.Dataset(DatasetName, null, null), Canceller.Token)
                .ContinueWith(t =>
                {
                    if (t.IsCanceled)
                    {
                        return;
                    }

                    if (t.IsFaulted)
                    {
                        Log.Error(TAG, $"Failed to fetch dataset {DatasetName} with error {t.Exception.Flatten().InnerException}.");
                        Toast.MakeText(this, "Failed to get performance information.", ToastLength.Short).Show();
                        return;
                    }

                    RunOnUiThread(() =>
                    {
                        // Change units.
                        var dataset = t
                                      .Result
                                      .dataset
                                      .Select(d => new DataPoint
                        {
                            Timestamp = d.Timestamp - TimestampOffset,
                            Value     = Converter.ChangeUnits(d.Value),
                        })
                                      .ToArray();

                        var minValue = dataset.Min(d => d.Value);
                        var min      = dataset.First(d => d.Value == minValue);
                        var maxValue = dataset.Max(d => d.Value);
                        var max      = dataset.First(d => d.Value == maxValue);
                        var width    = maxValue - minValue;

                        var datasetMap = dataset.ToDictionary(d => new BarModel
                        {
                            Value = d.Value,
                            ValueCaptionHidden = true,
                        });

                        var chart = new BarChartView(this)
                        {
                            ItemsSource  = datasetMap.Keys,
                            BarWidth     = 3,
                            BarOffset    = 1,
                            MinimumValue = min.Value - width / 2,
                            MaximumValue = max.Value + width / 2,
                        };

                        chart.AutoLevelsEnabled = false;
                        chart.AddLevelIndicator(min.Value, StringizeValue(min.Value));
                        chart.AddLevelIndicator(max.Value, StringizeValue(max.Value));

                        chart.BarClick += (sender, args) => {
                            DataPoint data = null;
                            if (!datasetMap.TryGetValue(args.Bar, out data))
                            {
                                return;
                            }

                            new AlertDialog.Builder(this)
                            .SetCancelable(false)
                            .SetTitle(UIConversion.FromMilliseconds(data.Timestamp).ToString())
                            .SetMessage(StringizeValue(data.Value))
                            .SetPositiveButton("OK", (s, e) => { })
                            .Create()
                            .Show();
                        };

                        SetContentView(chart, new ViewGroup.LayoutParams(
                                           ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)
                                       );
                    });
                });
            }
            catch (Exception e)
            {
                Toast.MakeText(this, $"Failed to get performance information for {DatasetName} for {Title}", ToastLength.Short).Show();
                Log.Error(TAG, $"Failed to start activity for dataset {DatasetName} with error {e}.");
                Finish();
            }
        }