public VerifiedParticipationPage(Protocol protocol, ParticipationRewardDatum participationRewardDatum)
        {
            Title = "Participation Verification";

            StackLayout contentLayout = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand,
                Padding = new Thickness(0, 25, 0, 0)
            };

            string requiredParticipationPercentage = Math.Round(protocol.RewardThreshold.GetValueOrDefault() * 100, 0) + "%";
            string participationPercentage = Math.Round(participationRewardDatum.Participation * 100, 0) + "%";
            
            if (protocol.RewardThreshold == null)
            {
                contentLayout.Children.Add(
                    new Label
                    {
                        Text = "Verified Participation Level",
                        FontSize = 20,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    });

                contentLayout.Children.Add(
                    new Label
                    {
                        Text = participationPercentage,
                        FontSize = 50,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    }
                );
            }
            else
            {
                bool reward = participationRewardDatum.Participation >= protocol.RewardThreshold.GetValueOrDefault();

                contentLayout.Children.Add(
                    new Image
                    {
                        HorizontalOptions = LayoutOptions.FillAndExpand,
                        Source = ImageSource.FromFile(reward ? "check.png" : "x.png")
                    });

                contentLayout.Children.Add(
                    new Label
                    {
                        Text = "Participant should " + (reward ? "" : "not ") + "be rewarded. This study requires " + requiredParticipationPercentage + " participation, and the participant is at " + participationPercentage + ".",
                        FontSize = 20,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    });
            }

            Content = new ScrollView
            {
                Content = contentLayout
            };
        }
示例#2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SensusUI.ProbesPage"/> class.
        /// </summary>
        /// <param name="protocol">Protocol to display probes for.</param>
        public ProbesPage(Protocol protocol)
        {
            _protocol = protocol;

            Title = "Probes";

            _probesList = new ListView
            {
                IsPullToRefreshEnabled = true
            };

            _probesList.ItemTemplate = new DataTemplate(typeof(TextCell));
            _probesList.ItemTemplate.SetBinding(TextCell.TextProperty, new Binding(".", converter: new ProbeTextValueConverter()));
            _probesList.ItemTemplate.SetBinding(TextCell.TextColorProperty, new Binding(".", converter: new ProbeTextColorValueConverter()));
            _probesList.ItemTemplate.SetBinding(TextCell.DetailProperty, new Binding(".", converter: new ProbeDetailValueConverter()));
            _probesList.ItemTapped += async (o, e) =>
                {
                    ProbePage probePage = new ProbePage(e.Item as Probe);
                    probePage.Disappearing += (oo, ee) => { Bind(); };  // rebind the probes page to pick up changes in the probe
                    await Navigation.PushAsync(probePage);
                    _probesList.SelectedItem = null;
                };

            _probesList.Refreshing += (o, e) =>
            {
                Bind();
                _probesList.IsRefreshing = false;
            };

            Bind();

            ToolbarItems.Add(new ToolbarItem("All", null, async () =>
                {
                    if(await DisplayAlert("Enable All Probes", "Are you sure you want to enable all probes?", "Yes", "No"))
                    {
                        foreach(Probe probe in _protocol.Probes)
                            if(UiBoundSensusServiceHelper.Get(true).EnableProbeWhenEnablingAll(probe))
                                probe.Enabled = true;

                        Bind();
                    }
                }));

            ToolbarItems.Add(new ToolbarItem("None", null, async () =>
                {
                    if(await DisplayAlert("Disable All Probes", "Are you sure you want to disable all probes?", "Yes", "No"))
                    {
                        foreach(Probe probe in _protocol.Probes)
                            probe.Enabled = false;

                        Bind();
                    }
                }));

            Content = _probesList;
        }
示例#3
0
        public ProtocolReportDatum(DateTimeOffset timestamp, string error, string warning, string misc, Protocol protocol)
            : base(timestamp)
        {
            _error = error == null ? "" : error;
            _warning = warning == null ? "" : warning;
            _misc = misc == null ? "" : misc;
            _operatingSystem = SensusServiceHelper.Get().OperatingSystem;
            _probeParticipation = new Dictionary<string, float>();

            foreach (Probe probe in protocol.Probes.Where(probe => probe.GetParticipation() != null).OrderBy(probe => probe.DisplayName))
                _probeParticipation.Add(probe.DisplayName, probe.GetParticipation().GetValueOrDefault());
        }
示例#4
0
        public static void CreateAsync(string name, Action<Protocol> callback)
        {
            Probe.GetAllAsync(probes =>
                {
                    Protocol protocol = new Protocol(name);

                    foreach (Probe probe in probes)
                        protocol.AddProbe(probe);

                    SensusServiceHelper.Get().RegisterProtocol(protocol);

                    if (callback != null)
                        callback(protocol);
                });
        }
示例#5
0
        public static void CreateAsync(string name, Action<Protocol> callback)
        {
            new Thread(() =>
                {
                    Probe.GetAllAsync(probes =>
                        {
                            Protocol protocol = new Protocol(name);

                            foreach (Probe probe in probes)
                                protocol.AddProbe(probe);

                            callback(protocol);
                        });
                    
                }).Start();
        }
示例#6
0
        public static void ExecuteActionUponProtocolAuthentication(Protocol protocol, Action successAction, Action failAction = null)
        {
            if (protocol.LockPasswordHash == "")
                successAction();
            else
            {
                SensusServiceHelper.Get().PromptForInputAsync(
                    "Authenticate \"" + protocol.Name + "\"", 
                    new TextInput("Protocol Password:"******"The password you entered was not correct.");

                                if (failAction != null)
                                    failAction();
                            }
                        }
                    });
            }
        }
        public ParticipationReportDetailsPage(Protocol protocol)
        {
            Title = "Participation Details";

            StackLayout contentLayout = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.StartAndExpand
            };

            foreach (Probe probe in protocol.Probes.Where(probe => probe.GetParticipation() != null).OrderBy(probe => probe.GetParticipation()))
            {
                float participation = probe.GetParticipation().GetValueOrDefault();

                contentLayout.Children.Add(new StackLayout
                    {
                        Orientation = StackOrientation.Vertical,
                        VerticalOptions = LayoutOptions.FillAndExpand,
                        Children =
                        {
                            new Label
                            {
                                Text = probe.DisplayName + ":  " + Math.Round(participation * 100, 0) + "%",
                                FontSize = 20
                            },
                            new ProgressBar
                            {
                                Progress = participation
                            }
                        }
                    });
            }

            Content = new ScrollView
            {
                Content = contentLayout
            };
        }
示例#8
0
        public ParticipationReportPage(Protocol protocol, ParticipationRewardDatum participationRewardDatum, bool displayDatumQrCode)
        {
            Title = protocol.Name;

            #if __IOS__
            string howToIncreaseScore = "You can increase your score by opening Sensus more often and responding to questions that Sensus asks you.";
            #elif __ANDROID__
            string howToIncreaseScore = "You can increase your score by allowing Sensus to run continuously and responding to questions that Sensus asks you.";
            #elif WINDOWS_PHONE
            string userNotificationMessage = null; // TODO:  How to increase score?
            #else
            #error "Unrecognized platform."
            #endif

            StackLayout contentLayout = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand,
                Padding = new Thickness(0, 25, 0, 0),
                Children =
                {
                    new Label
                    {
                        Text = "Participation Level",
                        FontSize = 20,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    },
                    new Label
                    {
                        Text = Math.Round(participationRewardDatum.Participation * 100, 0) + "%",
                        FontSize = 50,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    },
                    new Label
                    {
                        Text = "This score reflects your participation level over the past " + (protocol.ParticipationHorizonDays == 1 ? "day" : protocol.ParticipationHorizonDays + " days") + "." +
                        (displayDatumQrCode ? " Anyone can verify your participation by tapping \"Scan Participation Barcode\" on their device and scanning the following barcode:" : ""),
                        FontSize = 20,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    }
                }
            };

            if (displayDatumQrCode)
            {
                Label expirationLabel = new Label
                {
                    FontSize = 15,
                    HorizontalOptions = LayoutOptions.CenterAndExpand
                };

                contentLayout.Children.Add(expirationLabel);

                Timer timer = new Timer(1000);

                timer.Elapsed += (o, e) =>
                {
                    Device.BeginInvokeOnMainThread(() =>
                        {
                            int secondsLeftBeforeBarcodeExpiration = (int)(SensusServiceHelper.PARTICIPATION_VERIFICATION_TIMEOUT_SECONDS - (DateTimeOffset.UtcNow - participationRewardDatum.Timestamp).TotalSeconds);

                            if (secondsLeftBeforeBarcodeExpiration <= 0)
                            {
                                expirationLabel.TextColor = Color.Red;
                                expirationLabel.Text = "Barcode has expired. Please reopen this page to renew it.";
                                timer.Stop();
                            }
                            else
                            {
                                --secondsLeftBeforeBarcodeExpiration;
                                expirationLabel.Text = "Barcode will expire in " + secondsLeftBeforeBarcodeExpiration + " second" + (secondsLeftBeforeBarcodeExpiration == 1 ? "" : "s") + ".";
                            }
                        });
                };

                timer.Start();

                Disappearing += (o, e) =>
                {
                    timer.Stop();
                };

                contentLayout.Children.Add(new Image
                    {
                        Source = SensusServiceHelper.Get().GetQrCodeImageSource(protocol.RemoteDataStore.GetDatumKey(participationRewardDatum)),
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    });
            }

            contentLayout.Children.Add(new Label
                {
                    Text = howToIncreaseScore,
                    FontSize = 20,
                    HorizontalOptions = LayoutOptions.CenterAndExpand
                });

            if (!string.IsNullOrWhiteSpace(protocol.ContactEmail))
            {
                Button emailStudyManagerButton = new Button
                {
                    Text = "Email Study Manager",
                    FontSize = 20
                };

                emailStudyManagerButton.Clicked += (o, e) =>
                {
                    SensusServiceHelper.Get().SendEmailAsync(protocol.ContactEmail, "Help with Sensus study:  " + protocol.Name,
                        "Hello - " + Environment.NewLine +
                        Environment.NewLine +
                        "I am having trouble with a Sensus study. The name of the study is \"" + protocol.Name + "\"." + Environment.NewLine +
                        Environment.NewLine +
                        "Here is why I am sending this email:  ");
                };

                contentLayout.Children.Add(emailStudyManagerButton);
            }

            Button viewParticipationDetailsButton = new Button
            {
                Text = "View Participation Details",
                FontSize = 20
            };

            viewParticipationDetailsButton.Clicked += async (o, e) =>
            {
                await Navigation.PushAsync(new ParticipationReportDetailsPage(protocol));
            };

            contentLayout.Children.Add(viewParticipationDetailsButton);

            Content = new ScrollView
            {
                Content = contentLayout
            };
        }
示例#9
0
 public bool ProtocolShouldBeRunning(Protocol protocol)
 {
     return _runningProtocolIds.Contains(protocol.Id);
 }
示例#10
0
 public void RegisterProtocol(Protocol protocol)
 {
     lock (_locker)
         if (!_stopped && !_registeredProtocols.Contains(protocol))
         {
             _registeredProtocols.Add(protocol);
             SaveAsync();
         }
 }
示例#11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SensusUI.DataStorePage"/> class.
        /// </summary>
        /// <param name="protocol">Protocol to which data store is to be bound.</param>
        /// <param name="dataStore">Data store to display.</param>
        /// <param name="local">If set to <c>true</c>, the data store will be treated as a local data store.</param>
        /// <param name="newDataStore">If set to <c>true</c>, the data store will be treated as a new data store.</param>
        public DataStorePage(Protocol protocol, DataStore dataStore, bool local, bool newDataStore)
        {
            Title = (local ? "Local" : "Remote") + " Data Store";

            List<View> views = new List<View>();

            views.Add(new ContentView
                {
                    Content = new Label
                    {
                        Text = dataStore.DisplayName,
                        FontSize = 20,
                        FontAttributes = FontAttributes.Italic,
                        TextColor = Color.Accent,
                        HorizontalOptions = LayoutOptions.Center
                    },
                    Padding = new Thickness(0, 10, 0, 10)
                });

            // property stacks all come from the data store passed in (i.e., a copy of the original on the protocol, if there is one)
            views.AddRange(UiProperty.GetPropertyStacks(dataStore));

            StackLayout buttonStack = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand
            };

            views.Add(buttonStack);

            // clearing only applies to local data stores that already exist on protocols and are clearable. new local data stores don't have this option.
            if (local && !newDataStore && protocol.LocalDataStore.Clearable)
            {
                Button clearButton = new Button
                {
                    Text = "Clear",
                    HorizontalOptions = LayoutOptions.FillAndExpand,
                    FontSize = 20
                };

                clearButton.Clicked += async (o, e) =>
                {
                    if (await DisplayAlert("Clear data from " + protocol.LocalDataStore.DisplayName + "?", "This action cannot be undone.", "Clear", "Cancel"))
                        protocol.LocalDataStore.Clear();  // clear the protocol's local data store
                };

                buttonStack.Children.Add(clearButton);
            }

            // sharing only applies to local data stores that already exist on protocols. new local data stores don't have this option.
            if (local && !newDataStore)
            {
                Button shareLocalDataButton = new Button
                {
                    Text = "Share",
                    HorizontalOptions = LayoutOptions.FillAndExpand,
                    FontSize = 20
                };

                shareLocalDataButton.Clicked += async (o, e) =>
                {
                    await Navigation.PushAsync(new ShareLocalDataStorePage(protocol.LocalDataStore));
                };

                buttonStack.Children.Add(shareLocalDataButton);
            }

            Button okayButton = new Button
            {
                Text = "OK",
                HorizontalOptions = LayoutOptions.FillAndExpand,
                FontSize = 20
            };

            okayButton.Clicked += async (o, e) =>
            {
                if (local)
                    protocol.LocalDataStore = dataStore as LocalDataStore;
                else
                    protocol.RemoteDataStore = dataStore as RemoteDataStore;

                await Navigation.PopAsync();
            };

            buttonStack.Children.Add(okayButton);

            StackLayout contentLayout = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand
            };

            foreach (View view in views)
                contentLayout.Children.Add(view);

            Content = new ScrollView
            {
                Content = contentLayout
            };
        }
示例#12
0
 public void UnregisterProtocol(Protocol protocol)
 {
     lock (_locker)
     {
         protocol.Stop();
         _registeredProtocols.Remove(protocol);
         SaveAsync();
     }
 }
示例#13
0
        /// <summary>
        /// Converts JSON to a Protocol object. Private because Protocols should always be serialized as encrypted binary codes, and this function works with unencrypted strings (it's called in service of the former).
        /// </summary>
        /// <param name="json">JSON to deserialize.</param>
        private static void DisplayFromJsonAsync(string json)
        {
            new Thread(() =>
            {
                try
                {
                    #region allow protocols to be opened across platforms by manually editing the namespaces in the JSON
                    string newJSON;
                    switch (SensusServiceHelper.Get().GetType().Name)
                    {
                    case "AndroidSensusServiceHelper":
                        newJSON = json.Replace(".iOS", ".Android").Replace(".WinPhone", ".Android");
                        break;

                    case "iOSSensusServiceHelper":
                        newJSON = json.Replace(".Android", ".iOS").Replace(".WinPhone", ".iOS");
                        break;

                    case "WinPhone":
                        newJSON = json.Replace(".Android", ".WinPhone").Replace(".iOS", ".WinPhone");
                        break;

                    default:
                        throw new SensusException("Attempted to deserialize JSON into unknown service helper type:  " + SensusServiceHelper.Get().GetType().FullName);
                    }

                    if (newJSON == json)
                    {
                        SensusServiceHelper.Get().Logger.Log("No cross-platform conversion required for service helper JSON.", LoggingLevel.Normal, typeof(Protocol));
                    }
                    else
                    {
                        SensusServiceHelper.Get().Logger.Log("Performed cross-platform conversion of service helper JSON.", LoggingLevel.Normal, typeof(Protocol));
                        json = newJSON;
                    }
                    #endregion

                    Protocol protocol             = null;
                    ManualResetEvent protocolWait = new ManualResetEvent(false);

                    // always deserialize protocols on the main thread (e.g., since a looper might be required for android)
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        try
                        {
                            protocol = JsonConvert.DeserializeObject <Protocol>(json, SensusServiceHelper.JSON_SERIALIZER_SETTINGS);
                        }
                        catch (Exception ex)
                        {
                            SensusServiceHelper.Get().Logger.Log("Error while deserializing protocol:  " + ex.Message, LoggingLevel.Normal, typeof(Protocol));
                        }
                        finally
                        {
                            protocolWait.Set();
                        }
                    });

                    protocolWait.WaitOne();

                    if (protocol == null)
                    {
                        SensusServiceHelper.Get().Logger.Log("Failed to deserialize protocol.", LoggingLevel.Normal, typeof(Protocol));
                        SensusServiceHelper.Get().FlashNotificationAsync("Failed to deserialize protocol.");
                        return;
                    }
                    else
                    {
                        Action <Protocol> StartProtocol = p =>
                        {
                            Device.BeginInvokeOnMainThread(async() =>
                            {
                                if (!(App.Current.MainPage.Navigation.NavigationStack.Last() is ProtocolsPage))
                                {
                                    await App.Current.MainPage.Navigation.PushAsync(new ProtocolsPage());
                                }

                                p.StartWithUserAgreement("You just opened a protocol named \"" + p.Name + "\" within Sensus." + (string.IsNullOrWhiteSpace(p.StartupAgreement) ? "" : " Please read the following terms and conditions."));
                            });
                        };

                        Protocol existingProtocol = SensusServiceHelper.Get().RegisteredProtocols.FirstOrDefault(p => p.Id == protocol.Id);

                        if (existingProtocol == null)
                        {
                            Probe.GetAllAsync(probes =>
                            {
                                // add any probes for the current platform that didn't come through when deserializing. for example, android has a listening WLAN probe, but iOS has a polling WLAN probe. neither will come through on the other platform when deserializing, since the types are not defined.
                                List <Type> deserializedProbeTypes = protocol.Probes.Select(p => p.GetType()).ToList();

                                foreach (Probe probe in probes)
                                {
                                    if (!deserializedProbeTypes.Contains(probe.GetType()))
                                    {
                                        SensusServiceHelper.Get().Logger.Log("Adding missing probe to protocol:  " + probe.GetType().FullName, LoggingLevel.Normal, typeof(Protocol));
                                        protocol.AddProbe(probe);
                                    }
                                }

                                // reset the random time anchor -- we shouldn't use the same one that someone else used
                                protocol.ResetRandomTimeAnchor();

                                // reset the storage directory
                                protocol.StorageDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), protocol.Id);
                                if (!Directory.Exists(protocol.StorageDirectory))
                                {
                                    Directory.CreateDirectory(protocol.StorageDirectory);
                                }

                                SensusServiceHelper.Get().RegisterProtocol(protocol);

                                StartProtocol(protocol);
                            });
                        }
                        else if (existingProtocol.Running)
                        {
                            SensusServiceHelper.Get().FlashNotificationAsync("Protocol \"" + existingProtocol.Name + "\" is already running.");
                        }
                        else
                        {
                            StartProtocol(existingProtocol);
                        }
                    }
                }
                catch (Exception ex)
                {
                    SensusServiceHelper.Get().Logger.Log("Failed to deserialize/display protocol from JSON:  " + ex.Message, LoggingLevel.Normal, typeof(Protocol));
                    SensusServiceHelper.Get().FlashNotificationAsync("Failed to deserialize and/or display protocol.");
                }
            }).Start();
        }
示例#14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SensusUI.ProtocolPage"/> class.
        /// </summary>
        /// <param name="protocol">Protocol to display.</param>
        public ProtocolPage(Protocol protocol)
        {
            _protocol = protocol;

            Title = "Protocol";

            List<View> views = new List<View>();

            views.AddRange(UiProperty.GetPropertyStacks(_protocol));

            #region data stores
            Button editLocalDataStoreButton = new Button
            {
                Text = "Local Data Store",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                IsEnabled = !_protocol.Running
            };

            editLocalDataStoreButton.Clicked += async (o, e) =>
                {
                    if (_protocol.LocalDataStore != null)
                        await Navigation.PushAsync(new DataStorePage(_protocol, _protocol.LocalDataStore.Copy(), true, false));
                };

            Button createLocalDataStoreButton = new Button
            {
                Text = "+",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.End,
                IsEnabled = !_protocol.Running
            };

            createLocalDataStoreButton.Clicked += (o, e) => CreateDataStore(true);

            StackLayout localDataStoreStack = new StackLayout
            {
                Orientation = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children = { editLocalDataStoreButton, createLocalDataStoreButton }
            };

            views.Add(localDataStoreStack);

            Button editRemoteDataStoreButton = new Button
            {
                Text = "Remote Data Store",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                IsEnabled = !_protocol.Running
            };

            editRemoteDataStoreButton.Clicked += async (o, e) =>
                {
                    if (_protocol.RemoteDataStore != null)
                        await Navigation.PushAsync(new DataStorePage(_protocol, _protocol.RemoteDataStore.Copy(), false, false));
                };

            Button createRemoteDataStoreButton = new Button
            {
                Text = "+",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.End,
                IsEnabled = !_protocol.Running
            };

            createRemoteDataStoreButton.Clicked += (o, e) => CreateDataStore(false);

            StackLayout remoteDataStoreStack = new StackLayout
            {
                Orientation = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children = { editRemoteDataStoreButton, createRemoteDataStoreButton }
            };

            views.Add(remoteDataStoreStack);
            #endregion

            #region points of interest
            Button pointsOfInterestButton = new Button
                {
                    Text = "Points of Interest",
                    FontSize = 20
                };

            pointsOfInterestButton.Clicked += async (o, e) =>
                {
                    await Navigation.PushAsync(new PointsOfInterestPage(
                        _protocol.PointsOfInterest,
                        () => UiBoundSensusServiceHelper.Get(true).SaveAsync()));
                };

            views.Add(pointsOfInterestButton);
            #endregion

            #region view probes
            Button viewProbesButton = new Button
            {
                Text = "Probes",
                FontSize = 20
            };

            viewProbesButton.Clicked += async (o, e) =>
                {
                    await Navigation.PushAsync(new ProbesPage(_protocol));
                };

            views.Add(viewProbesButton);
            #endregion

            _protocolRunningChangedAction = (o, running) =>
                {
                    Device.BeginInvokeOnMainThread(() =>
                        {
                            editLocalDataStoreButton.IsEnabled = createLocalDataStoreButton.IsEnabled = editRemoteDataStoreButton.IsEnabled = createRemoteDataStoreButton.IsEnabled = !running;
                        });
                };

            StackLayout stack = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand
            };

            foreach (View view in views)
                stack.Children.Add(view);

            Button lockButton = new Button
            {
                Text = _protocol.LockPasswordHash == "" ? "Lock" : "Unlock",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.FillAndExpand
            };

            lockButton.Clicked += (o, e) =>
            {
                if (lockButton.Text == "Lock")
                {
                    UiBoundSensusServiceHelper.Get(true).PromptForInputAsync("Create password to lock protocol:", false, password =>
                        {
                            if (password == null)
                                return;
                            else if (string.IsNullOrWhiteSpace(password))
                                UiBoundSensusServiceHelper.Get(true).FlashNotificationAsync("Please enter a non-empty password.");
                            else
                            {
                                _protocol.LockPasswordHash = UiBoundSensusServiceHelper.Get(true).GetHash(password);
                                Device.BeginInvokeOnMainThread(() => lockButton.Text = "Unlock");
                            }
                        });
                }
                else if (lockButton.Text == "Unlock")
                {
                    _protocol.LockPasswordHash = "";
                    lockButton.Text = "Lock";
                }
            };

            stack.Children.Add(lockButton);

            Content = new ScrollView
            {
                Content = stack
            };                        
        }
示例#15
0
 public void UnregisterProtocol(Protocol protocol)
 {
     lock (_registeredProtocols)
     {
         protocol.Stop();
         _registeredProtocols.Remove(protocol);
     }
 }
        public ParticipationReportPage(Protocol protocol)
        {
            Title = protocol.Name;

            #if __IOS__
            string howToIncreaseScore = "You can increase your score by opening Sensus more often and responding to questions that Sensus asks you.";
            #elif __ANDROID__
            string howToIncreaseScore = "You can increase your score by allowing Sensus to run continuously and responding to questions that Sensus asks you.";
            #elif WINDOWS_PHONE
            string userNotificationMessage = null; // TODO:  How to increase score?
            #else
            #error "Unrecognized platform."
            #endif

            Button helpButton = null;
            if (!string.IsNullOrWhiteSpace(protocol.ContactEmail))
            {
                helpButton = new Button
                {
                    Text = "Email Study Manager",
                    FontSize = 20
                };

                helpButton.Clicked += (o, e) =>
                {
                    UiBoundSensusServiceHelper.Get(true).SendEmailAsync(protocol.ContactEmail, "Help with study:  " + protocol.Name, "Hello - " + Environment.NewLine + Environment.NewLine + "I am having the following problem:" + Environment.NewLine + Environment.NewLine + "[DESCRIBE YOUR PROBLEM HERE]");
                };
            }

            StackLayout contentLayout = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand,
                Padding = new Thickness(0, 50, 0, 0),
                Children =
                {
                    new Label
                    {
                        Text = "Participation Level",
                        FontSize = 20,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    },
                    new Label
                    {
                        Text = Math.Round(protocol.OverallParticipationLevel * 100, 0) + "%",
                        FontSize = 75,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    },
                    new Label
                    {
                        Text = "This score reflects your overall participation level in the \"" + protocol.Name + "\" study over the past " + (protocol.ParticipationHorizonDays == 1 ? "day" : protocol.ParticipationHorizonDays + " days") + ". " + howToIncreaseScore + (helpButton == null ? "" : " If you have questions, please click the button below to email the study manager."),
                        FontSize = 20,
                        HorizontalOptions = LayoutOptions.CenterAndExpand
                    }
                }
            };

            if (helpButton != null)
                contentLayout.Children.Add(helpButton);

            Content = new ScrollView
            {
                Content = contentLayout
            };
        }
 public override float GetFullActivityHealthTestsPerDay(Protocol protocol)
 {
     return 60000 * 60 * 24 / (float)SensusServiceHelper.HEALTH_TEST_DELAY_MS;
 }
示例#18
0
 public void RegisterProtocol(Protocol protocol)
 {
     lock (_registeredProtocols)
     {
         if (!_registeredProtocols.Contains(protocol))
             _registeredProtocols.Add(protocol);
     }
 }
示例#19
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SensusUI.ProtocolPage"/> class.
        /// </summary>
        /// <param name="protocol">Protocol to display.</param>
        public ProtocolPage(Protocol protocol)
        {
            _protocol = protocol;

            Title = "Protocol";

            List<View> views = new List<View>();

            views.AddRange(UiProperty.GetPropertyStacks(_protocol));

            #region data stores
            string localDataStoreSize = null;
            try
            {
                if (protocol.LocalDataStore != null)
                {
                    if (protocol.LocalDataStore is RamLocalDataStore)
                        localDataStoreSize = (protocol.LocalDataStore as RamLocalDataStore).DataCount + " items";
                    else if (protocol.LocalDataStore is FileLocalDataStore)
                        localDataStoreSize = Math.Round(SensusServiceHelper.GetDirectorySizeMB((protocol.LocalDataStore as FileLocalDataStore).StorageDirectory), 1) + " MB";
                }
            }
            catch (Exception)
            {
            }

            Button editLocalDataStoreButton = new Button
            {
                Text = "Local Data Store" + (localDataStoreSize == null ? "" : " (" + localDataStoreSize + ")"),
                FontSize = 20,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                IsEnabled = !_protocol.Running
            };

            editLocalDataStoreButton.Clicked += async (o, e) =>
            {
                if (_protocol.LocalDataStore != null)
                    await Navigation.PushAsync(new DataStorePage(_protocol, _protocol.LocalDataStore.Copy(), true, false));
            };

            Button createLocalDataStoreButton = new Button
            {
                Text = "+",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.End,
                IsEnabled = !_protocol.Running
            };

            createLocalDataStoreButton.Clicked += (o, e) => CreateDataStore(true);

            StackLayout localDataStoreStack = new StackLayout
            {
                Orientation = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children = { editLocalDataStoreButton, createLocalDataStoreButton }
            };

            views.Add(localDataStoreStack);

            Button editRemoteDataStoreButton = new Button
            {
                Text = "Remote Data Store",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                IsEnabled = !_protocol.Running
            };

            editRemoteDataStoreButton.Clicked += async (o, e) =>
            {
                if (_protocol.RemoteDataStore != null)
                    await Navigation.PushAsync(new DataStorePage(_protocol, _protocol.RemoteDataStore.Copy(), false, false));
            };

            Button createRemoteDataStoreButton = new Button
            {
                Text = "+",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.End,
                IsEnabled = !_protocol.Running
            };

            createRemoteDataStoreButton.Clicked += (o, e) => CreateDataStore(false);

            StackLayout remoteDataStoreStack = new StackLayout
            {
                Orientation = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children = { editRemoteDataStoreButton, createRemoteDataStoreButton }
            };

            views.Add(remoteDataStoreStack);
            #endregion

            #region points of interest
            Button pointsOfInterestButton = new Button
            {
                Text = "Points of Interest",
                FontSize = 20
            };

            pointsOfInterestButton.Clicked += async (o, e) =>
            {
                await Navigation.PushAsync(new PointsOfInterestPage(_protocol.PointsOfInterest));
            };

            views.Add(pointsOfInterestButton);
            #endregion

            #region view probes
            Button viewProbesButton = new Button
            {
                Text = "Probes",
                FontSize = 20
            };

            viewProbesButton.Clicked += async (o, e) =>
            {
                await Navigation.PushAsync(new ProbesPage(_protocol));
            };

            views.Add(viewProbesButton);
            #endregion

            _protocolRunningChangedAction = (o, running) =>
            {
                Device.BeginInvokeOnMainThread(() =>
                    {
                        editLocalDataStoreButton.IsEnabled = createLocalDataStoreButton.IsEnabled = editRemoteDataStoreButton.IsEnabled = createRemoteDataStoreButton.IsEnabled = !running;
                    });
            };

            StackLayout stack = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand
            };

            foreach (View view in views)
                stack.Children.Add(view);

            Button lockButton = new Button
            {
                Text = _protocol.LockPasswordHash == "" ? "Lock" : "Unlock",
                FontSize = 20,
                HorizontalOptions = LayoutOptions.FillAndExpand
            };

            lockButton.Clicked += (o, e) =>
            {
                if (lockButton.Text == "Lock")
                {
                    SensusServiceHelper.Get().PromptForInputAsync(
                        "Lock Protocol",
                        new SingleLineTextInput("Password:"******"Please enter a non-empty password.");
                            else
                            {
                                _protocol.LockPasswordHash = SensusServiceHelper.Get().GetHash(password);
                                Device.BeginInvokeOnMainThread(() => lockButton.Text = "Unlock");
                            }
                        });
                }
                else if (lockButton.Text == "Unlock")
                {
                    _protocol.LockPasswordHash = "";
                    lockButton.Text = "Lock";
                }
            };

            stack.Children.Add(lockButton);

            Content = new ScrollView
            {
                Content = stack
            };                        
        }
 public override float GetFullActivityHealthTestsPerDay(Protocol protocol)
 {
     return protocol.FullActivityHealthTestsPerDay;
 }
示例#21
0
        private void ExecuteActionUponProtocolAuthentication(Protocol protocol, Action action)
        {
            if (protocol.LockPasswordHash == "")
                action();
            else
                UiBoundSensusServiceHelper.Get(true).PromptForInputAsync("Enter protocol password:"******"The password you entered was not correct.");
                    });
        }
示例#22
0
        private void ExecuteActionUponProtocolAuthentication(Protocol protocol, Action action)
        {
            if (protocol.LockPasswordHash == "")
                action();
            else
                UiBoundSensusServiceHelper.Get(true).PromptForInputAsync(

                    "Authenticate",

                    new TextInput("Protocol Password:"******"The password you entered was not correct.");
                    });
        }
示例#23
0
        public static void DisplayAndStartAsync(Protocol protocol)
        {
            new Thread(() =>
                {
                    if (protocol == null)
                        SensusServiceHelper.Get().FlashNotificationAsync("Protocol is empty. Cannot display or start it.");
                    else if (protocol.Running)
                        SensusServiceHelper.Get().FlashNotificationAsync("You are already participating in \"" + protocol.Name + "\".");
                    else
                    {                        
                        Device.BeginInvokeOnMainThread(async () =>
                            {
                                // display the protocols page if it isn't already up
                                ProtocolsPage protocolsPage = null;
                                Page topPage = App.Current.MainPage.Navigation.NavigationStack.Last();
                                if (topPage is ProtocolsPage)
                                    protocolsPage = topPage as ProtocolsPage;
                                else
                                {
                                    protocolsPage = new ProtocolsPage();
                                    await App.Current.MainPage.Navigation.PushAsync(protocolsPage);
                                }

                                // ask user to start protocol
                                protocol.StartWithUserAgreementAsync("You just opened \"" + protocol.Name + "\" within Sensus.", () =>
                                    {
                                        Device.BeginInvokeOnMainThread(() =>
                                            {
                                                // rebind to pick up any color changes
                                                protocolsPage.Bind();
                                            });
                                    });
                            });
                    }

                }).Start();
        }