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 }; }
/// <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; }
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()); }
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); }); }
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(); }
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 }; }
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 }; }
public bool ProtocolShouldBeRunning(Protocol protocol) { return _runningProtocolIds.Contains(protocol.Id); }
public void RegisterProtocol(Protocol protocol) { lock (_locker) if (!_stopped && !_registeredProtocols.Contains(protocol)) { _registeredProtocols.Add(protocol); SaveAsync(); } }
/// <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 }; }
public void UnregisterProtocol(Protocol protocol) { lock (_locker) { protocol.Stop(); _registeredProtocols.Remove(protocol); SaveAsync(); } }
/// <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(); }
/// <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 }; }
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; }
public void RegisterProtocol(Protocol protocol) { lock (_registeredProtocols) { if (!_registeredProtocols.Contains(protocol)) _registeredProtocols.Add(protocol); } }
/// <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; }
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."); }); }
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."); }); }
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(); }