/// <summary> /// Initializes a new instance of the <see cref="SensusUI.ProbePage"/> class. /// </summary> /// <param name="probe">Probe to display.</param> public ProbePage(Probe probe) { Title = "Probe"; StackLayout contentLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; foreach (StackLayout stack in UiProperty.GetPropertyStacks(probe)) contentLayout.Children.Add(stack); #region script probes if (probe is ScriptProbe) { Button editScriptsButton = new Button { Text = "Edit Scripts", FontSize = 20 }; editScriptsButton.Clicked += async (o, e) => { await Navigation.PushAsync(new ScriptRunnersPage(probe as ScriptProbe)); }; contentLayout.Children.Add(editScriptsButton); } #endregion #region proximity probe if (probe is IPointsOfInterestProximityProbe) { Button editTriggersButton = new Button { Text = "Edit Triggers", FontSize = 20, HorizontalOptions = LayoutOptions.FillAndExpand }; contentLayout.Children.Add(editTriggersButton); editTriggersButton.Clicked += async (o, e) => { await Navigation.PushAsync(new ProximityTriggersPage(probe as IPointsOfInterestProximityProbe)); }; } #endregion #region anonymization List<PropertyInfo> anonymizableProperties = probe.DatumType.GetProperties().Where(property => property.GetCustomAttribute<Anonymizable>() != null).ToList(); if (anonymizableProperties.Count > 0) { contentLayout.Children.Add(new Label { Text = "Anonymization", FontSize = 20, FontAttributes = FontAttributes.Italic, TextColor = Color.Accent, HorizontalOptions = LayoutOptions.Center }); List<StackLayout> anonymizablePropertyStacks = new List<StackLayout>(); foreach (PropertyInfo anonymizableProperty in anonymizableProperties) { Anonymizable anonymizableAttribute = anonymizableProperty.GetCustomAttribute<Anonymizable>(true); Label propertyLabel = new Label { Text = anonymizableAttribute.PropertyDisplayName ?? anonymizableProperty.Name + ":", FontSize = 20, HorizontalOptions = LayoutOptions.Start }; // populate a picker of anonymizers for the current property Picker anonymizerPicker = new Picker { Title = "Select Anonymizer", HorizontalOptions = LayoutOptions.FillAndExpand }; anonymizerPicker.Items.Add("Do Not Anonymize"); foreach (Anonymizer anonymizer in anonymizableAttribute.AvailableAnonymizers) anonymizerPicker.Items.Add(anonymizer.DisplayText); anonymizerPicker.SelectedIndexChanged += (o, e) => { Anonymizer selectedAnonymizer = null; if (anonymizerPicker.SelectedIndex > 0) selectedAnonymizer = anonymizableAttribute.AvailableAnonymizers[anonymizerPicker.SelectedIndex - 1]; // subtract one from the selected index since the JsonAnonymizer's collection of anonymizers start after the "None" option within the picker. probe.Protocol.JsonAnonymizer.SetAnonymizer(anonymizableProperty, selectedAnonymizer); }; // set the picker's index to the current anonymizer (or "Do Not Anonymize" if there is no current) Anonymizer currentAnonymizer = probe.Protocol.JsonAnonymizer.GetAnonymizer(anonymizableProperty); int currentIndex = 0; if (currentAnonymizer != null) currentIndex = anonymizableAttribute.AvailableAnonymizers.IndexOf(currentAnonymizer) + 1; anonymizerPicker.SelectedIndex = currentIndex; StackLayout anonymizablePropertyStack = new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { propertyLabel, anonymizerPicker } }; anonymizablePropertyStacks.Add(anonymizablePropertyStack); } foreach (StackLayout anonymizablePropertyStack in anonymizablePropertyStacks.OrderBy(s => (s.Children[0] as Label).Text)) contentLayout.Children.Add(anonymizablePropertyStack); } #endregion Content = new ScrollView { Content = contentLayout }; }
public override bool EnableProbeWhenEnablingAll(Probe probe) { // polling for locations doesn't work very well in iOS, since it depends on the user. don't enable probes that need location polling by default. return !(probe is PollingLocationProbe) && !(probe is PollingSpeedProbe) && !(probe is PollingPointsOfInterestProximityProbe); }
private void AddProbe(Probe probe) { probe.Protocol = this; // since the new probe was just bound to this protocol, we need to let this protocol know about this probe's default anonymization preferences. foreach (PropertyInfo anonymizableProperty in probe.DatumType.GetProperties().Where(property => property.GetCustomAttribute<Anonymizable>() != null)) { Anonymizable anonymizableAttribute = anonymizableProperty.GetCustomAttribute<Anonymizable>(true); _jsonAnonymizer.SetAnonymizer(anonymizableProperty, anonymizableAttribute.DefaultAnonymizer); } _probes.Add(probe); }
/// <summary> /// The user can enable all probes at once. When this is done, it doesn't make sense to enable, e.g., the /// listening location probe as well as the polling location probe. This method allows the platforms to /// decide which probes to enable when enabling all probes. /// </summary> /// <returns><c>true</c>, if probe should be enabled, <c>false</c> otherwise.</returns> /// <param name="probe">Probe.</param> public abstract bool EnableProbeWhenEnablingAll(Probe probe);
public override bool EnableProbeWhenEnablingAll(Probe probe) { // listening for locations doesn't work very well in android, since it conflicts with polling and uses more power. don't enable probes that need location listening by default. return !(probe is ListeningLocationProbe) && !(probe is ListeningSpeedProbe) && !(probe is ListeningPointsOfInterestProximityProbe); }
/// <summary> /// Initializes a new instance of the <see cref="SensusUI.ProbePage"/> class. /// </summary> /// <param name="probe">Probe to display.</param> public ProbePage(Probe probe) { Title = "Probe"; StackLayout contentLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; string type = ""; if (probe is ListeningProbe) type = "Listening"; else if (probe is PollingProbe) type = "Polling"; contentLayout.Children.Add(new ContentView { Content = new Label { Text = probe.DisplayName + (type == "" ? "" : " (" + type + ")"), FontSize = 20, FontAttributes = FontAttributes.Italic, TextColor = Color.Accent, HorizontalOptions = LayoutOptions.Center }, Padding = new Thickness(0, 10, 0, 10) }); foreach (StackLayout stack in UiProperty.GetPropertyStacks(probe)) contentLayout.Children.Add(stack); #region script probes if (probe is ScriptProbe) { ScriptProbe scriptProbe = probe as ScriptProbe; Button editScriptsButton = new Button { Text = "Edit Scripts", FontSize = 20 }; contentLayout.Children.Add(editScriptsButton); editScriptsButton.Clicked += async (o, e) => { await Navigation.PushAsync(new ScriptRunnersPage(scriptProbe)); }; Button shareScriptButton = new Button { Text = "Share Definition", FontSize = 20 }; contentLayout.Children.Add(shareScriptButton); shareScriptButton.Clicked += (o, e) => { string sharePath = SensusServiceHelper.Get().GetSharePath(".json"); using (StreamWriter shareFile = new StreamWriter(sharePath)) { shareFile.WriteLine(JsonConvert.SerializeObject(probe, SensusServiceHelper.JSON_SERIALIZER_SETTINGS)); shareFile.Close(); } SensusServiceHelper.Get().ShareFileAsync(sharePath, "Probe Definition", "application/json"); }; } #endregion #region proximity probe if (probe is IPointsOfInterestProximityProbe) { Button editTriggersButton = new Button { Text = "Edit Triggers", FontSize = 20, HorizontalOptions = LayoutOptions.FillAndExpand }; contentLayout.Children.Add(editTriggersButton); editTriggersButton.Clicked += async (o, e) => { await Navigation.PushAsync(new ProximityTriggersPage(probe as IPointsOfInterestProximityProbe)); }; } #endregion #region anonymization List<PropertyInfo> anonymizableProperties = probe.DatumType.GetProperties().Where(property => property.GetCustomAttribute<Anonymizable>() != null).ToList(); if (anonymizableProperties.Count > 0) { contentLayout.Children.Add(new Label { Text = "Anonymization", FontSize = 20, FontAttributes = FontAttributes.Italic, TextColor = Color.Accent, HorizontalOptions = LayoutOptions.Center }); List<StackLayout> anonymizablePropertyStacks = new List<StackLayout>(); foreach (PropertyInfo anonymizableProperty in anonymizableProperties) { Anonymizable anonymizableAttribute = anonymizableProperty.GetCustomAttribute<Anonymizable>(true); Label propertyLabel = new Label { Text = anonymizableAttribute.PropertyDisplayName ?? anonymizableProperty.Name + ":", FontSize = 20, HorizontalOptions = LayoutOptions.Start }; // populate a picker of anonymizers for the current property Picker anonymizerPicker = new Picker { Title = "Select Anonymizer", HorizontalOptions = LayoutOptions.FillAndExpand }; anonymizerPicker.Items.Add("Do Not Anonymize"); foreach (Anonymizer anonymizer in anonymizableAttribute.AvailableAnonymizers) anonymizerPicker.Items.Add(anonymizer.DisplayText); anonymizerPicker.SelectedIndexChanged += (o, e) => { Anonymizer selectedAnonymizer = null; if (anonymizerPicker.SelectedIndex > 0) selectedAnonymizer = anonymizableAttribute.AvailableAnonymizers[anonymizerPicker.SelectedIndex - 1]; // subtract one from the selected index since the JsonAnonymizer's collection of anonymizers start after the "None" option within the picker. probe.Protocol.JsonAnonymizer.SetAnonymizer(anonymizableProperty, selectedAnonymizer); }; // set the picker's index to the current anonymizer (or "Do Not Anonymize" if there is no current) Anonymizer currentAnonymizer = probe.Protocol.JsonAnonymizer.GetAnonymizer(anonymizableProperty); int currentIndex = 0; if (currentAnonymizer != null) currentIndex = anonymizableAttribute.AvailableAnonymizers.IndexOf(currentAnonymizer) + 1; anonymizerPicker.SelectedIndex = currentIndex; StackLayout anonymizablePropertyStack = new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { propertyLabel, anonymizerPicker } }; anonymizablePropertyStacks.Add(anonymizablePropertyStack); } foreach (StackLayout anonymizablePropertyStack in anonymizablePropertyStacks.OrderBy(s => (s.Children[0] as Label).Text)) contentLayout.Children.Add(anonymizablePropertyStack); } #endregion Content = new ScrollView { Content = contentLayout }; }
/// <summary> /// Initializes a new instance of the <see cref="SensusUI.AddScriptTriggerPage"/> class. /// </summary> /// <param name="scriptRunner">Script runner to add trigger to.</param> public AddScriptTriggerPage(ScriptRunner scriptRunner) { _scriptRunner = scriptRunner; Title = "Add Trigger"; List<Probe> enabledProbes = _scriptRunner.Probe.Protocol.Probes.Where(p => p != _scriptRunner.Probe && p.Enabled).ToList(); if (enabledProbes.Count == 0) { Content = new Label { Text = "No enabled probes. Please enable them before creating triggers.", FontSize = 20 }; return; } StackLayout contentLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; Label probeLabel = new Label { Text = "Probe:", FontSize = 20 }; Picker probePicker = new Picker { Title = "Select Probe", HorizontalOptions = LayoutOptions.FillAndExpand }; foreach (Probe enabledProbe in enabledProbes) probePicker.Items.Add(enabledProbe.DisplayName); contentLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { probeLabel, probePicker } }); StackLayout triggerDefinitionLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; contentLayout.Children.Add(triggerDefinitionLayout); Switch changeSwitch = new Switch(); Switch regexSwitch = new Switch(); Switch fireRepeatedlySwitch = new Switch(); Switch ignoreFirstDatumSwitch = new Switch(); TimePicker startTimePicker = new TimePicker { HorizontalOptions = LayoutOptions.FillAndExpand }; TimePicker endTimePicker = new TimePicker { HorizontalOptions = LayoutOptions.FillAndExpand }; probePicker.SelectedIndexChanged += (o, e) => { _selectedProbe = null; _selectedDatumProperty = null; _conditionValue = null; triggerDefinitionLayout.Children.Clear(); if (probePicker.SelectedIndex < 0) return; _selectedProbe = enabledProbes[probePicker.SelectedIndex]; PropertyInfo[] datumProperties = _selectedProbe.DatumType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttributes<ProbeTriggerProperty>().Count() > 0).ToArray(); if(datumProperties.Length == 0) return; #region datum property picker Label datumPropertyLabel = new Label { Text = "Property:", FontSize = 20 }; Picker datumPropertyPicker = new Picker { Title = "Select Datum Property", HorizontalOptions = LayoutOptions.FillAndExpand }; foreach (PropertyInfo datumProperty in datumProperties) { ProbeTriggerProperty triggerProperty = datumProperty.GetCustomAttributes<ProbeTriggerProperty>().First(); datumPropertyPicker.Items.Add(triggerProperty.Name ?? datumProperty.Name); } triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { datumPropertyLabel, datumPropertyPicker } }); #endregion #region condition picker (same for all datum types) Label conditionLabel = new Label { Text = "Condition:", FontSize = 20 }; Picker conditionPicker = new Picker { Title = "Select Condition", HorizontalOptions = LayoutOptions.FillAndExpand }; TriggerValueCondition[] conditions = Enum.GetValues(typeof(TriggerValueCondition)) as TriggerValueCondition[]; foreach (TriggerValueCondition condition in conditions) conditionPicker.Items.Add(condition.ToString()); conditionPicker.SelectedIndexChanged += (oo, ee) => { if (conditionPicker.SelectedIndex < 0) return; _selectedCondition = conditions[conditionPicker.SelectedIndex]; }; triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { conditionLabel, conditionPicker } }); #endregion #region condition value for comparison, based on selected datum property -- includes change calculation (for double datum) and regex (for string datum) StackLayout conditionValueStack = new StackLayout { Orientation = StackOrientation.Vertical, HorizontalOptions = LayoutOptions.FillAndExpand }; triggerDefinitionLayout.Children.Add(conditionValueStack); datumPropertyPicker.SelectedIndexChanged += (oo, ee) => { _selectedDatumProperty = null; _conditionValue = null; conditionValueStack.Children.Clear(); if (datumPropertyPicker.SelectedIndex < 0) return; _selectedDatumProperty = datumProperties[datumPropertyPicker.SelectedIndex]; ProbeTriggerProperty datumTriggerAttribute = _selectedDatumProperty.GetCustomAttribute<ProbeTriggerProperty>(); View conditionValueStackView = null; bool allowChangeCalculation = false; bool allowRegularExpression = false; if (datumTriggerAttribute is ListProbeTriggerProperty) { Picker conditionValuePicker = new Picker { Title = "Select Condition Value", HorizontalOptions = LayoutOptions.FillAndExpand }; object[] items = (datumTriggerAttribute as ListProbeTriggerProperty).Items; foreach (object item in items) conditionValuePicker.Items.Add(item.ToString()); conditionValuePicker.SelectedIndexChanged += (ooo, eee) => { if (conditionValuePicker.SelectedIndex < 0) return; _conditionValue = items[conditionValuePicker.SelectedIndex]; }; conditionValueStackView = conditionValuePicker; } else if (datumTriggerAttribute is NumberProbeTriggerProperty) { Entry entry = new Entry { Keyboard = Keyboard.Numeric, HorizontalOptions = LayoutOptions.FillAndExpand }; entry.TextChanged += (ooo, eee) => { double value; if (double.TryParse(eee.NewTextValue, out value)) _conditionValue = value; }; conditionValueStackView = entry; allowChangeCalculation = true; } else if (datumTriggerAttribute is TextProbeTriggerProperty) { Entry entry = new Entry { Keyboard = Keyboard.Default, HorizontalOptions = LayoutOptions.FillAndExpand }; entry.TextChanged += (ooo, eee) => _conditionValue = eee.NewTextValue; conditionValueStackView = entry; allowRegularExpression = true; } else if (datumTriggerAttribute is BooleanProbeTriggerProperty) { Switch booleanSwitch = new Switch(); booleanSwitch.Toggled += (ooo, eee) => _conditionValue = eee.Value; conditionValueStackView = booleanSwitch; } Label conditionValueStackLabel = new Label { Text = "Value:", FontSize = 20 }; conditionValueStack.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { conditionValueStackLabel, conditionValueStackView } }); #region change calculation if (allowChangeCalculation) { Label changeLabel = new Label { Text = "Change:", FontSize = 20 }; changeSwitch.IsToggled = false; conditionValueStack.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { changeLabel, changeSwitch } }); } #endregion #region regular expression if (allowRegularExpression) { Label regexLabel = new Label { Text = "Regular Expression:", FontSize = 20 }; regexSwitch.IsToggled = false; conditionValueStack.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { regexLabel, regexSwitch } }); } #endregion }; datumPropertyPicker.SelectedIndex = 0; #endregion #region fire repeatedly Label fireRepeatedlyLabel = new Label { Text = "Fire Repeatedly:", FontSize = 20 }; fireRepeatedlySwitch.IsToggled = false; triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { fireRepeatedlyLabel, fireRepeatedlySwitch } }); #endregion #region ignore first datum Label ignoreFirstDatumLabel = new Label { Text = "Ignore First Datum:", FontSize = 20 }; ignoreFirstDatumSwitch.IsToggled = false; triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { ignoreFirstDatumLabel, ignoreFirstDatumSwitch } }); #endregion #region start/end times Label startTimeLabel = new Label { Text = "Start Time:", FontSize = 20 }; startTimePicker.Time = new TimeSpan(8, 0, 0); triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { startTimeLabel, startTimePicker } }); Label endTimeLabel = new Label { Text = "End Time:", FontSize = 20 }; endTimePicker.Time = new TimeSpan(21, 0, 0); triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { endTimeLabel, endTimePicker } }); #endregion }; probePicker.SelectedIndex = 0; Button okButton = new Button { Text = "OK", FontSize = 20 }; okButton.Clicked += async (o, e) => { try { _scriptRunner.Triggers.Add(new SensusService.Probes.User.Trigger(_selectedProbe, _selectedDatumProperty, _selectedCondition, _conditionValue, changeSwitch.IsToggled, fireRepeatedlySwitch.IsToggled, regexSwitch.IsToggled, ignoreFirstDatumSwitch.IsToggled, startTimePicker.Time, endTimePicker.Time)); await Navigation.PopAsync(); } catch (Exception ex) { string message = "Failed to add trigger: " + ex.Message; UiBoundSensusServiceHelper.Get(true).FlashNotificationAsync(message); UiBoundSensusServiceHelper.Get(true).Logger.Log(message, LoggingLevel.Normal, GetType()); } }; contentLayout.Children.Add(okButton); Content = new ScrollView { Content = contentLayout }; }