diff --git a/NEWS b/NEWS index 42fbac2..5cd5a2c 100644 --- a/NEWS +++ b/NEWS @@ -36,7 +36,7 @@ feedbackd 0.4.1 --------------- Released August 2024 * Simplify udev rule installation -* Dont' fail tests with newer json-glib +* Don't fail tests with newer json-glib * Issues fixed: * https://source.puri.sm/Librem5/feedbackd/-/issues/79 * Contributors: @@ -50,7 +50,7 @@ Released June 2024 * Internal cleanups and restructuring to cater for different LED types. * Support RGB color mixing for multicolor leds -* Allow to use (camera) flash LEDs as notificaton LED +* Allow to use (camera) flash LEDs as notification LED * Immediately end "too noisy" feedbacks when switching profile levels * Issues fixed: * https://source.puri.sm/Librem5/feedbackd/-/issues/77 diff --git a/README.md b/README.md index f6fdf70..f7f031c 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ modified theme file in If multiple theme files exist, the selection logic follows these steps: 1. It picks an identifier from the devicetree, until none are left -1. It searches through the folders in `XDG_DATA_DIRS` in order of appearence, +1. It searches through the folders in `XDG_DATA_DIRS` in order of appearance, until none are left 1. If a theme file is found in the current location with the current name, **it will be chosen** and other themes are ignored. diff --git a/data/org.sigxcpu.Feedback.Haptic.xml b/data/org.sigxcpu.Feedback.Haptic.xml index ea6c4ee..4e2a192 100644 --- a/data/org.sigxcpu.Feedback.Haptic.xml +++ b/data/org.sigxcpu.Feedback.Haptic.xml @@ -19,7 +19,8 @@ Triggers the given vibration pattern on the haptic device. The pattern is a sequence of relative amplitude and duration pairs. - The amplitude must be between 0.0 and 1.0. + The amplitude must be between 0.0 and 1.0, durations are in + milliseconds. --> diff --git a/data/org.sigxcpu.feedbackd.gschema.xml b/data/org.sigxcpu.feedbackd.gschema.xml index df76971..732726b 100644 --- a/data/org.sigxcpu.feedbackd.gschema.xml +++ b/data/org.sigxcpu.feedbackd.gschema.xml @@ -28,7 +28,7 @@ false Prefer camera flash LED over notification LED - Prefer the (camera) flash LED over other notifiction LEDs. + Prefer the (camera) flash LED over other notification LEDs. diff --git a/debian/changelog b/debian/changelog index 9c5ca24..67e39c1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -33,9 +33,9 @@ feedbackd (0.6.0) experimental; urgency=medium [ Guido Günther ] * event-naming-spec: Fix section description - * event-naming-spec: Expand on notifiction events. + * event-naming-spec: Expand on notification events. We move them to the system category as the notification server - is a system component and add an event for now notifictions + is a system component and add an event for new notifications for the notification server to use * theme: Add notification-missed-new. We'll remove message-new-notification somewhat later to not break @@ -101,7 +101,7 @@ feedbackd (0.5.0) experimental; urgency=medium [ Guido Günther ] * packaging: Update lintian overrides * packaging: Install NEWS and README. They contain useful information - * packaging: Use pkgconf. It's prefered over pkg-config in Debian + * packaging: Use pkgconf. It's preferred over pkg-config in Debian * doc: Document gsettings used by feedbackd * udev: Add support for haptics on Oneplus Enchilada / Fajita. The spmi_haptics driver isn't in mainline Linux as of Linux 6.11. @@ -266,7 +266,7 @@ feedbackd (0.4.0) experimental; urgency=medium even if the device is suspended. * fbd-dev-led-qcom-multicolor: Support QCOM LPG LED multicolor. QCOM LPG LEDs can also operate in a multicolor fashion. - Re-use the probing sequence of multicolor LEDs and the hw_pattern + Reuse the probing sequence of multicolor LEDs and the hw_pattern configuration of single color QCOM LPG LEDs. * fbd-dev-leds: Probe QCOM HW LED types. Try first the QCOM hardware LED types which require the most features of @@ -486,7 +486,7 @@ feedbackd (0.0.2) experimental; urgency=medium * Include specifications in the documentation. Now that we can use markdown easily add them as they provide help to the developer what events exist, etc. - * dir-locals: Simlify consistent JS indenting + * dir-locals: Simplify consistent JS indenting * feedback-vibra: Fix indentation * tests: Test feedback theme name * feedback-theme: No need for constructed. @@ -700,13 +700,13 @@ feedbackd (0.0.0+git20210426) byzantium; urgency=medium * event: Make log-domain match source file name * tests: Run event tests too * event: Remove 'g' prefix from common C types. - This matchs phosh's style. + This matches phosh's style. * fbd-event: Add sender property. This allows us to store the DBus sender * fbd-manager: Keep DBus sender around * feedback-manager: Track DBus clients and end feedbacks if they go away. When the client goes away we build up a list of events to end feedback - for to make sure the hash table isn't modified in place. tThe alternative + for to make sure the hash table isn't modified in place. the alternative approach would be to disconnect the on_event_feedbacks_ended handler, duplicate the DBus signal emission and use g_hash_table_foreach_remove but that looks less robust than using the same code path. (Closes: #25) @@ -838,7 +838,7 @@ feedbackd (0.0.0+git20200714) amber-phone; urgency=medium [ Guido Günther ] * lfb-event: Clarify return values of `finished` functions. - They just inidicate that we talked to feedbackd successfully. + They just indicate that we talked to feedbackd successfully. * lfb-event: Connect done handler in async case too. Otherwise the event state is not updated properly * tests: Don't quit mainloop on event end. @@ -886,7 +886,7 @@ feedbackd (0.0.0+git20200707) amber-phone; urgency=medium trigger. * data: Use LED feedback for missed calls, IMs and SMS * Add generic missed notification. - This can be used e.g. by the shell for general purpose notifictions + This can be used e.g. by the shell for general purpose notifications but also for in app notifications of the foreground app. * feedback-manager: Add hint to select feedback profile per event. This e.g. allows events that are meant for haptic only to avoid diff --git a/doc/feedback-themes.rst b/doc/feedback-themes.rst index dea3682..12c583d 100644 --- a/doc/feedback-themes.rst +++ b/doc/feedback-themes.rst @@ -27,6 +27,7 @@ To build a theme you can use several different feedback types: - `Sound`: Plays a sound from the installed sound theme - `VibraRumble`: A single rumble using the haptic motor - `VibraPeriodic`: A periodic rumble using the haptic motor +- `VibraPattern`: A pattern specifying the rumbling of the haptic motor - `Led`: A LED blinking in a periodic pattern Sound feedback @@ -42,6 +43,16 @@ The `VibraRumble` feedback uses a single property - `duration`: The duration of the rumble in ms. +VibraPattern feedback +~~~~~~~~~~~~~~~~~~~~~ + +The `VibraPattern` feedback has these properties + +- `magnitudes`: The relative magnitude of each rumble ``[0, 1]`` as array of doubles. +- `durations`: The durations of each rumble in ms as array of unsigned integers. + +Both arrays must have the same length. + LED feedback ~~~~~~~~~~~~ @@ -51,7 +62,7 @@ The `Led` feedback type uses two properties to specify the way a LED blinks. `green`, `blue` and `white` as well as values in the RGB HEX format (`#RRGGBB`) where `RR`, `GG` and `BB` are two digit hex value between `00` and `FF` specifying the value of each component. E.g. `#00FFFF` corresponds to cyan color. -- `frequency`: The LEDs blinkinig frequencey in mHz. +- `frequency`: The LEDs blinkinig frequency in mHz. See also ======== diff --git a/doc/initialization.md b/doc/initialization.md index a5d58c1..843de94 100644 --- a/doc/initialization.md +++ b/doc/initialization.md @@ -8,7 +8,7 @@ call [func@Lfb.init]() with the id of your application (usually the desktop file name without the .desktop extension). For that you include the `libfeedback.h` header. Since the API is considered unstable at this point in time you need to acknowledge this by -definining `LIBFEEDBACK_USE_UNSTABLE_API`: +defining `LIBFEEDBACK_USE_UNSTABLE_API`: ```c #define LIBFEEDBACK_USE_UNSTABLE_API diff --git a/libfeedback/lfb-main.c b/libfeedback/lfb-main.c index b317305..7059f9e 100644 --- a/libfeedback/lfb-main.c +++ b/libfeedback/lfb-main.c @@ -28,7 +28,7 @@ lfb_cancel_feedbacks (void) while (g_hash_table_iter_next (&iter, &key, &value)) { guint id = GPOINTER_TO_UINT(key); g_hash_table_iter_remove (&iter); - g_debug ("Cancellling feedback on shutdown %d", id); + g_debug ("Cancelling feedback on shutdown %d", id); /* Need to use a sync call here since there might not be a main loop anymore */ lfb_gdbus_feedback_call_end_feedback_sync (_proxy, id, NULL, NULL); } diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index e330155..287f200 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -79,7 +79,7 @@ fbd_dev_led_multicolor_probe (FbdDevLed *led, GError **error) priv->blue_index = counter; counter++; } else { - g_warning ("Unsupport LED color index: %d %s", counter, index[i]); + g_warning ("Unsupported LED color index: %d %s", counter, index[i]); } } diff --git a/src/fbd-feedback-profile.c b/src/fbd-feedback-profile.c index 94cbb36..d1bb605 100644 --- a/src/fbd-feedback-profile.c +++ b/src/fbd-feedback-profile.c @@ -10,6 +10,7 @@ #include "fbd-feedback-profile.h" #include "fbd-feedback-sound.h" #include "fbd-feedback-led.h" +#include "fbd-feedback-vibra-pattern.h" #include "fbd-feedback-vibra-periodic.h" #include "fbd-feedback-vibra-rumble.h" @@ -85,6 +86,7 @@ feedback_get_type (JsonNode *feedback_node) /* Ensure all feedback types so the json parsing can use them */ g_type_ensure (FBD_TYPE_FEEDBACK_DUMMY); g_type_ensure (FBD_TYPE_FEEDBACK_LED); + g_type_ensure (FBD_TYPE_FEEDBACK_VIBRA_PATTERN); g_type_ensure (FBD_TYPE_FEEDBACK_VIBRA_PERIODIC); g_type_ensure (FBD_TYPE_FEEDBACK_VIBRA_RUMBLE); g_type_ensure (FBD_TYPE_FEEDBACK_SOUND); diff --git a/src/fbd-feedback-vibra-pattern.c b/src/fbd-feedback-vibra-pattern.c index b74c44c..4807ede 100644 --- a/src/fbd-feedback-vibra-pattern.c +++ b/src/fbd-feedback-vibra-pattern.c @@ -13,6 +13,8 @@ #include "fbd-feedback-vibra-priv.h" #include "fbd-feedback-manager.h" +#include + /** * FbdFeedbackVibraPattern: * @@ -41,7 +43,68 @@ typedef struct _FbdFeedbackVibraPattern { guint timer_id; } FbdFeedbackVibraPattern; -G_DEFINE_TYPE (FbdFeedbackVibraPattern, fbd_feedback_vibra_pattern, FBD_TYPE_FEEDBACK_VIBRA); +static void json_serializable_iface_init (JsonSerializableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (FbdFeedbackVibraPattern, fbd_feedback_vibra_pattern, + FBD_TYPE_FEEDBACK_VIBRA, + G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE, + json_serializable_iface_init)); + + +static gboolean +fbd_feedback_vibra_pattern_serializable_deserialize_property (JsonSerializable *serializable, + const gchar *property_name, + GValue *value, + GParamSpec *pspec, + JsonNode *property_node) +{ + if (g_strcmp0 (property_name, "magnitudes") == 0) { + if (JSON_NODE_TYPE (property_node) == JSON_NODE_ARRAY) { + JsonArray *array = json_node_get_array (property_node); + guint array_len = json_array_get_length (array); + g_autoptr (GArray) magnitudes = g_array_sized_new (FALSE, FALSE, sizeof (double), array_len); + + for (guint i = 0; i < array_len; i++) { + JsonNode *element_node = json_array_get_element (array, i); + + if (JSON_NODE_HOLDS_VALUE (element_node)) { + double magnitude; + + magnitude = json_node_get_double (element_node); + magnitude = MAX (0.0, MIN (magnitude, 1.0)); + g_array_append_val (magnitudes, magnitude); + } else { + return FALSE; + } + } + g_value_set_boxed (value, magnitudes); + return TRUE; + } + } else if (g_strcmp0 (property_name, "durations") == 0) { + if (JSON_NODE_TYPE (property_node) == JSON_NODE_ARRAY) { + JsonArray *array = json_node_get_array (property_node); + guint array_len = json_array_get_length (array); + g_autoptr (GArray) durations = g_array_sized_new (FALSE, FALSE, sizeof (guint), array_len); + + for (guint i = 0; i < array_len; i++) { + JsonNode *element_node = json_array_get_element (array, i); + + if (JSON_NODE_HOLDS_VALUE (element_node)) { + guint duration; + + duration = json_node_get_int (element_node); + g_array_append_val (durations, duration); + } else { + return FALSE; + } + } + g_value_set_boxed (value, durations); + return TRUE; + } + } + + return FALSE; +} static void @@ -157,6 +220,7 @@ on_timer_expired (gpointer data) self->pos++; if (self->pos == self->durations->len) { + self->pos = 0; self->timer_id = 0; return; } @@ -172,12 +236,11 @@ fbd_feedback_vibra_pattern_end_vibra (FbdFeedbackVibra *vibra) FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); FbdDevVibra *dev = fbd_feedback_manager_get_dev_vibra (manager); - if (self->timer_id) { - self->pos = 0; - g_clear_handle_id (&self->timer_id, g_source_remove); - } + self->pos = 0; + g_clear_handle_id (&self->timer_id, g_source_remove); - fbd_dev_vibra_stop (dev); + if (dev) + fbd_dev_vibra_stop (dev); } @@ -192,7 +255,9 @@ fbd_feedback_vibra_pattern_start_vibra (FbdFeedbackVibra *vibra) g_return_if_fail (self->magnitudes); g_return_if_fail (self->durations); g_return_if_fail (self->durations->len == self->magnitudes->len); - g_return_if_fail (self->pos == 0); + + if (self->pos) + fbd_feedback_vibra_pattern_end_vibra (FBD_FEEDBACK_VIBRA (self)); g_debug ("Pattern Vibra: %u elements", self->durations->len); @@ -225,6 +290,11 @@ fbd_feedback_vibra_pattern_finalize (GObject *object) G_OBJECT_CLASS (fbd_feedback_vibra_pattern_parent_class)->finalize (object); } +static void +json_serializable_iface_init (JsonSerializableIface *iface) +{ + iface->deserialize_property = fbd_feedback_vibra_pattern_serializable_deserialize_property; +} static void fbd_feedback_vibra_pattern_class_init (FbdFeedbackVibraPatternClass *klass) diff --git a/src/fbd-haptic-manager.c b/src/fbd-haptic-manager.c index a886f35..d1fb3c3 100644 --- a/src/fbd-haptic-manager.c +++ b/src/fbd-haptic-manager.c @@ -133,7 +133,7 @@ fbd_feedback_manager_handle_vibrate (LfbGdbusFeedbackHaptic *object, fbd_feedback_end (FBD_FEEDBACK_BASE (self->vibra)); if (fbd_dev_vibra_is_busy (vibra_dev)) { g_debug ("Haptic busy"); - /* If there's an event with haptic deny haptic patter */ + /* If there's an event with haptic deny haptic pattern */ lfb_gdbus_feedback_haptic_complete_vibrate (object, invocation, FALSE); return TRUE; } diff --git a/tests/meson.build b/tests/meson.build index f9d4264..20c9c74 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -14,6 +14,8 @@ if get_option('tests') test_env.set('MALLOC_CHECK_', '2') test_env.set('XDG_CONFIG_HOME', meson.current_source_dir() / 'data' / 'user-config') test_env.set('XDG_CONFIG_DIRS', meson.current_source_dir()) + # Override desktop so we don't depend on GNOME schemas in the tests + test_env.set('XDG_CURRENT_DESKTOP', 'doesnotexist') # Shared library Unit tests @@ -66,6 +68,7 @@ if get_option('tests') fbd_tests = [ 'fbd-feedback-led', 'fbd-feedback-profile', + 'fbd-feedback-vibra', 'fbd-feedback-theme', 'fbd-event', 'fbd-theme-expander', diff --git a/tests/test-fbd-feedback-vibra.c b/tests/test-fbd-feedback-vibra.c new file mode 100644 index 0000000..fca6845 --- /dev/null +++ b/tests/test-fbd-feedback-vibra.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0+ + * + * Author: Guido Günther + */ + +#define GMOBILE_USE_UNSTABLE_API +#include "fbd-feedback-manager.h" +#include "fbd-feedback-vibra-pattern.h" + +#include + + +static void +test_fbd_feedback_vibra_pattern (void) +{ + /* Create manager upfront so we can dispose it, otherwise creating + * any feedback would create it implicitly */ + FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); + g_autoptr (GError) err = NULL; + g_autoptr (JsonNode) node = NULL; + g_autoptr (GArray) durations = NULL, magnitudes = NULL; + GObject *object; + guint *duration; + double *magnitude; + + node = json_from_string("{" + " \"event-name\" : \"button-pressed\"," + " \"type\" : \"VibraPattern\"," + " \"magnitudes\" : [ 0.2, 1.0 ]," + " \"durations\" : [ 7, 3 ]" + "}", &err); + g_assert_no_error (err); + + object = json_gobject_deserialize (FBD_TYPE_FEEDBACK_VIBRA_PATTERN, node); + g_object_get (object, "durations", &durations, "magnitudes", &magnitudes, NULL); + + g_assert_nonnull(durations); + g_assert_nonnull(magnitudes); + + duration = &g_array_index (durations, guint, 0); + g_assert_cmpint (*duration, ==, 7); + duration = &g_array_index (durations, guint, 1); + g_assert_cmpint (*duration, ==, 3); + + magnitude = &g_array_index (magnitudes, double, 0); + g_assert_cmpfloat (*magnitude, ==, 0.2); + magnitude = &g_array_index (magnitudes, double, 1); + g_assert_cmpfloat (*magnitude, ==, 1.0); + + g_assert_finalize_object (object); + g_assert_finalize_object (manager); +} + + +gint +main (gint argc, gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func("/feedbackd/fbd/feedback-vibra/pattern", test_fbd_feedback_vibra_pattern); + + return g_test_run(); +}