Merge lp:~charlesk/indicator-power/lp-1470767-low-battery-sound into lp:indicator-power/15.10

Proposed by Charles Kerr on 2016-01-01
Status: Merged
Approved by: Ted Gould on 2016-01-07
Approved revision: 314
Merged at revision: 291
Proposed branch: lp:~charlesk/indicator-power/lp-1470767-low-battery-sound
Merge into: lp:indicator-power/15.10
Diff against target: 1500 lines (+939/-31)
20 files modified
CMakeLists.txt (+3/-1)
data/CMakeLists.txt (+9/-0)
debian/control (+3/-0)
src/CMakeLists.txt (+9/-1)
src/datafiles.c (+71/-0)
src/datafiles.h (+37/-0)
src/main.c (+14/-6)
src/notifier.c (+150/-4)
src/notifier.h (+6/-2)
src/service.c (+50/-9)
src/service.h (+6/-1)
src/sound-player-gst.c (+173/-0)
src/sound-player-gst.h (+70/-0)
src/sound-player.c (+45/-0)
src/sound-player.h (+72/-0)
tests/CMakeLists.txt (+14/-2)
tests/glib-fixture.h (+1/-1)
tests/sound-player-mock.c (+94/-0)
tests/sound-player-mock.h (+75/-0)
tests/test-notify.cc (+37/-4)
To merge this branch: bzr merge lp:~charlesk/indicator-power/lp-1470767-low-battery-sound
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve on 2016-01-04
Ted Gould (community) 2016-01-01 Approve on 2016-01-04
Review via email: mp+281460@code.launchpad.net

Commit message

Play a 'low battery' sound when the low battery notification is shown.

Description of the change

Play a 'low battery' sound when the low battery notification is shown.

Why so many LOC for this simple feature? Here's what changed:

1. Add dependency on GST, copy gst code from indicator-datetime code
to set the playing sound's role to "alert"

2. Install the low battery sound into CMAKE_INSTALL_DATADIR/indicator-power/sounds/ and add code to search the XDG data paths to find the sound because (a) after discussion in #phablet with seb128 and Jouni we don't want to install this single-purpose sound in sounds/ubuntu/ but (b) we still want it to be possible to override the sound by putting something in XDG_DATA_HOME.

3. Create a SoundPlayer interface so a mock version can be plugged
in during unit tests instead of poking gst. (This is most of the LOC
since indicator-power is written in C)

4. Change startup steps so that dependency injection can be used
on the Notifier class to specify the SoundPlayer.

5. Add an AccountsServices DBus proxy so we can honor silent mode

6. Update tests

To post a comment you must log in.
301. By charles kerr <email address hidden> on 2016-01-02

fix another touched file's copyright date

302. By charles kerr <email address hidden> on 2016-01-02

create a data/sounds/ directory in the repo to hold Low battery.ogg

We may be adding sounds for when we transition to battery
charging/discharging, so set up a sounds/ directory now.

303. By charles kerr <email address hidden> on 2016-01-02

use a symbolic constant for the low battery sound's filename

304. By charles kerr <email address hidden> on 2016-01-02

honor com.ubuntu.touch.AccountsService.Sound.SilentMode

305. By charles kerr <email address hidden> on 2016-01-02

update copyright dates on changed files (again)

306. By charles kerr <email address hidden> on 2016-01-02

handle service_set_notifier(NULL) gracefully

Ted Gould (ted) wrote :

It seems you don't have <email address hidden> registered with LP, that makes it not associate the commits with your UID.

Little fixes. Seems big, but lots of boilerplate, we need to get this indicator converted to C++11 ;-)

307. By Charles Kerr on 2016-01-04

add 'bzr fixes' metainfo to the branch

308. By Charles Kerr on 2016-01-04

add build-dep to accountsservice-ubuntu-schemas instead of bundling com.ubuntu.touch.AccountsService.Sound.xml into our source tree

309. By Charles Kerr on 2016-01-04

add a leak safeguard to accounts_service_sound_proxy

310. By Charles Kerr on 2016-01-04

assume we're in silent mode if we can't get an accounts-service proxy

311. By Charles Kerr on 2016-01-04

fix copy-paste typo

312. By Charles Kerr on 2016-01-04

move sound-player-mock into the tests/ directory

Charles Kerr (charlesk) wrote :

> It seems you don't have <email address hidden> registered with LP, that makes it not associate the commits with your UID.

Oh dear. I may have broken my config last week. Fixed with a new bzr whoami for r307.

> we need to get this indicator converted to C++11 ;-)

I thought this a couple of times while writing the GObject/GInterface boilerplate, but didn't want to MP that for OTA 9 :)

Inline comments' responses are inline

Ted Gould (ted) wrote :

Thanks! +1

review: Approve
313. By Charles Kerr on 2016-01-04

don't disable the warning sound when AccountServices is completely unavailable

Ted Gould (ted) wrote :

Still +1 :-)

review: Approve
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
314. By Charles Kerr on 2016-01-04

demote a spurious warning to a debug message

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-07-21 21:08:29 +0000
3+++ CMakeLists.txt 2016-01-04 20:26:17 +0000
4@@ -7,7 +7,8 @@
5 set(PACKAGE ${CMAKE_PROJECT_NAME})
6 set(GETTEXT_PACKAGE "indicator-power")
7 add_definitions (-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}"
8- -DGNOMELOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}")
9+ -DGNOMELOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}"
10+ -DLOW_BATTERY_SOUND="Low battery.ogg")
11
12 option (enable_tests "Build the package's automatic tests." ON)
13 option (enable_lcov "Generate lcov code coverage reports." ON)
14@@ -38,6 +39,7 @@
15 gio-unix-2.0>=2.36
16 gudev-1.0>=204
17 libnotify>=0.7.6
18+ gstreamer-1.0>=1.2
19 url-dispatcher-1>=1)
20
21 include_directories (SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS})
22
23=== modified file 'data/CMakeLists.txt'
24--- data/CMakeLists.txt 2014-09-09 03:58:48 +0000
25+++ data/CMakeLists.txt 2016-01-04 20:26:17 +0000
26@@ -88,3 +88,12 @@
27
28 install (FILES "${UNITY_INDICATOR_FILE}"
29 DESTINATION "${UNITY_INDICATOR_DIR}")
30+
31+##
32+## Sounds
33+##
34+
35+# where to install
36+set (DATA_HOME "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}")
37+message (STATUS "${DATA_HOME} is the sounds/ install dir")
38+install (DIRECTORY sounds DESTINATION ${DATA_HOME})
39
40=== added directory 'data/sounds'
41=== added file 'data/sounds/Low battery.ogg'
42Binary files data/sounds/Low battery.ogg 1970-01-01 00:00:00 +0000 and data/sounds/Low battery.ogg 2016-01-04 20:26:17 +0000 differ
43=== modified file 'debian/control'
44--- debian/control 2015-02-25 14:49:06 +0000
45+++ debian/control 2016-01-04 20:26:17 +0000
46@@ -7,7 +7,10 @@
47 libglib2.0-dev (>= 2.36),
48 libgudev-1.0-dev,
49 liburl-dispatcher1-dev,
50+ libgstreamer1.0-dev,
51 python:any,
52+# for com.ubuntu.touch.AccountsService.Sound.xml
53+ accountsservice-ubuntu-schemas,
54 # for packaging
55 debhelper (>= 9),
56 dh-translations,
57
58=== modified file 'src/CMakeLists.txt'
59--- src/CMakeLists.txt 2015-05-20 15:34:26 +0000
60+++ src/CMakeLists.txt 2016-01-04 20:26:17 +0000
61@@ -6,13 +6,16 @@
62 # handwritten sources
63 set(SERVICE_MANUAL_SOURCES
64 brightness.c
65+ datafiles.c
66 device-provider-mock.c
67 device-provider-upower.c
68 device-provider.c
69 device.c
70 notifier.c
71 testing.c
72- service.c)
73+ service.c
74+ sound-player.c
75+ sound-player-gst.c)
76
77 # generated sources
78 include(GdbusCodegen)
79@@ -29,6 +32,11 @@
80 com.canonical.indicator.power
81 Dbus
82 ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.power.Testing.xml)
83+add_gdbus_codegen_with_namespace(SERVICE_GENERATED_SOURCES dbus-accounts-sound
84+ com.ubuntu.touch
85+ Dbus
86+ /usr/share/accountsservice/interfaces/com.ubuntu.touch.AccountsService.Sound.xml)
87+
88 # add the bin dir to our include path so the code can find the generated header files
89 include_directories(${CMAKE_CURRENT_BINARY_DIR})
90
91
92=== added file 'src/datafiles.c'
93--- src/datafiles.c 1970-01-01 00:00:00 +0000
94+++ src/datafiles.c 2016-01-04 20:26:17 +0000
95@@ -0,0 +1,71 @@
96+/*
97+ * Copyright 2016 Canonical Ltd.
98+ *
99+ * This program is free software: you can redistribute it and/or modify it
100+ * under the terms of the GNU General Public License version 3, as published
101+ * by the Free Software Foundation.
102+ *
103+ * This program is distributed in the hope that it will be useful, but
104+ * WITHOUT ANY WARRANTY; without even the implied warranties of
105+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
106+ * PURPOSE. See the GNU General Public License for more details.
107+ *
108+ * You should have received a copy of the GNU General Public License along
109+ * with this program. If not, see <http://www.gnu.org/licenses/>.
110+ *
111+ * Authors:
112+ * Charles Kerr <charles.kerr@canonical.com>
113+ */
114+
115+#include "datafiles.h"
116+
117+static const gchar*
118+get_directory_prefix_for_type (DatafileType type)
119+{
120+ switch (type)
121+ {
122+ case DATAFILE_TYPE_SOUND:
123+ return "sounds";
124+
125+ default:
126+ g_critical("unknown type");
127+ return "";
128+ }
129+}
130+
131+static gchar*
132+test_directory_for_file(const char* dir, DatafileType type, const char* basename)
133+{
134+ gchar* filename = g_build_filename(dir,
135+ GETTEXT_PACKAGE,
136+ get_directory_prefix_for_type(type),
137+ basename,
138+ NULL);
139+
140+ g_debug("looking for \"%s\" at \"%s\"", basename, filename);
141+ if (g_file_test(filename, G_FILE_TEST_EXISTS))
142+ return filename;
143+
144+ g_free(filename);
145+ return NULL;
146+}
147+
148+gchar*
149+datafile_find(DatafileType type, const char * basename)
150+{
151+ gchar * filename;
152+ const gchar * user_data_dir;
153+ const gchar * const * system_data_dirs;
154+ gsize i;
155+
156+ user_data_dir = g_get_user_data_dir();
157+ if ((filename = test_directory_for_file(user_data_dir, type, basename)))
158+ return filename;
159+
160+ system_data_dirs = g_get_system_data_dirs();
161+ for (i=0; system_data_dirs && system_data_dirs[i]; ++i)
162+ if ((filename = test_directory_for_file(system_data_dirs[i], type, basename)))
163+ return filename;
164+
165+ return NULL;
166+}
167
168=== added file 'src/datafiles.h'
169--- src/datafiles.h 1970-01-01 00:00:00 +0000
170+++ src/datafiles.h 2016-01-04 20:26:17 +0000
171@@ -0,0 +1,37 @@
172+/*
173+ * Copyright 2016 Canonical Ltd.
174+ *
175+ * This program is free software: you can redistribute it and/or modify it
176+ * under the terms of the GNU General Public License version 3, as published
177+ * by the Free Software Foundation.
178+ *
179+ * This program is distributed in the hope that it will be useful, but
180+ * WITHOUT ANY WARRANTY; without even the implied warranties of
181+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
182+ * PURPOSE. See the GNU General Public License for more details.
183+ *
184+ * You should have received a copy of the GNU General Public License along
185+ * with this program. If not, see <http://www.gnu.org/licenses/>.
186+ *
187+ * Authors:
188+ * Charles Kerr <charles.kerr@canonical.com>
189+ */
190+
191+#ifndef __INDICATOR_POWER_DATAFILES_H__
192+#define __INDICATOR_POWER_DATAFILES_H__
193+
194+#include <gio/gio.h>
195+
196+G_BEGIN_DECLS
197+
198+typedef enum
199+{
200+ DATAFILE_TYPE_SOUND
201+}
202+DatafileType;
203+
204+gchar* datafile_find(DatafileType type, const char * basename);
205+
206+G_END_DECLS
207+
208+#endif /* __INDICATOR_POWER_DATAFILES_H__ */
209
210=== modified file 'src/main.c'
211--- src/main.c 2014-10-14 19:09:32 +0000
212+++ src/main.c 2016-01-04 20:26:17 +0000
213@@ -1,8 +1,5 @@
214 /*
215- * Copyright 2013 Canonical Ltd.
216- *
217- * Authors:
218- * Charles Kerr <charles.kerr@canonical.com>
219+ * Copyright 2013-2016 Canonical Ltd.
220 *
221 * This program is free software: you can redistribute it and/or modify it
222 * under the terms of the GNU General Public License version 3, as published
223@@ -15,6 +12,9 @@
224 *
225 * You should have received a copy of the GNU General Public License along
226 * with this program. If not, see <http://www.gnu.org/licenses/>.
227+ *
228+ * Authors:
229+ * Charles Kerr <charles.kerr@canonical.com>
230 */
231
232 #include <locale.h>
233@@ -23,7 +23,9 @@
234 #include <glib/gi18n.h>
235
236 #include "device.h"
237+#include "notifier.h"
238 #include "service.h"
239+#include "sound-player-gst.h"
240 #include "testing.h"
241
242 /***
243@@ -40,6 +42,8 @@
244 int
245 main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED)
246 {
247+ IndicatorPowerSoundPlayer * sound_player;
248+ IndicatorPowerNotifier * notifier;
249 IndicatorPowerService * service;
250 IndicatorPowerTesting * testing;
251 GMainLoop * loop;
252@@ -50,7 +54,9 @@
253 textdomain (GETTEXT_PACKAGE);
254
255 /* run */
256- service = indicator_power_service_new (NULL);
257+ sound_player = indicator_power_sound_player_gst_new ();
258+ notifier = indicator_power_notifier_new (sound_player);
259+ service = indicator_power_service_new(NULL, notifier);
260 testing = indicator_power_testing_new (service);
261 loop = g_main_loop_new (NULL, FALSE);
262 g_signal_connect (service, INDICATOR_POWER_SERVICE_SIGNAL_NAME_LOST,
263@@ -59,7 +65,9 @@
264
265 /* cleanup */
266 g_main_loop_unref (loop);
267+ g_clear_object (&testing);
268 g_clear_object (&service);
269- g_clear_object (&testing);
270+ g_clear_object (&notifier);
271+ g_clear_object (&sound_player);
272 return 0;
273 }
274
275=== modified file 'src/notifier.c'
276--- src/notifier.c 2014-10-15 01:58:28 +0000
277+++ src/notifier.c 2016-01-04 20:26:17 +0000
278@@ -1,5 +1,5 @@
279 /*
280- * Copyright 2014 Canonical Ltd.
281+ * Copyright 2014-2016 Canonical Ltd.
282 *
283 * This program is free software: you can redistribute it and/or modify it
284 * under the terms of the GNU General Public License version 3, as published
285@@ -17,9 +17,12 @@
286 * Charles Kerr <charles.kerr@canonical.com>
287 */
288
289+#include "datafiles.h"
290+#include "dbus-accounts-sound.h"
291 #include "dbus-battery.h"
292 #include "dbus-shared.h"
293 #include "notifier.h"
294+#include "sound-player.h"
295
296 #include <url-dispatcher.h>
297
298@@ -46,10 +49,12 @@
299 {
300 PROP_0,
301 PROP_BATTERY,
302+ PROP_SOUND_PLAYER,
303 LAST_PROP
304 };
305
306 #define PROP_BATTERY_NAME "battery"
307+#define PROP_SOUND_PLAYER_NAME "sound-player"
308
309 static GParamSpec * properties[LAST_PROP];
310
311@@ -77,6 +82,12 @@
312
313 gboolean caps_queried;
314 gboolean actions_supported;
315+
316+ IndicatorPowerSoundPlayer * sound_player;
317+
318+ GCancellable * cancellable;
319+ DbusAccountsServiceSound * accounts_service_sound_proxy;
320+ gboolean accounts_service_sound_proxy_pending;
321 }
322 IndicatorPowerNotifierPrivate;
323
324@@ -131,6 +142,82 @@
325 }
326
327 /***
328+**** Sounds
329+***/
330+
331+static void
332+on_sound_proxy_ready (GObject * source_object G_GNUC_UNUSED,
333+ GAsyncResult * res,
334+ gpointer gself)
335+{
336+ GError * error;
337+ DbusAccountsServiceSound * proxy;
338+
339+ error = NULL;
340+ proxy = dbus_accounts_service_sound_proxy_new_for_bus_finish (res, &error);
341+ if (error != NULL)
342+ {
343+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
344+ {
345+ get_priv(gself)->accounts_service_sound_proxy_pending = FALSE;
346+ g_debug("%s Couldn't find accounts service sound proxy: %s", G_STRLOC, error->message);
347+ }
348+
349+ g_clear_error(&error);
350+ }
351+ else
352+ {
353+ IndicatorPowerNotifier * const self = INDICATOR_POWER_NOTIFIER(gself);
354+ priv_t * const p = get_priv (self);
355+ g_clear_object (&p->accounts_service_sound_proxy);
356+ p->accounts_service_sound_proxy = proxy;
357+ p->accounts_service_sound_proxy_pending = FALSE;
358+ }
359+}
360+
361+static gboolean
362+silent_mode (IndicatorPowerNotifier * self)
363+{
364+ priv_t * const p = get_priv (self);
365+
366+ /* if we don't have a proxy yet, assume we're in silent mode
367+ as a "do no harm" level of response */
368+ if (p->accounts_service_sound_proxy_pending)
369+ return TRUE;
370+
371+ return (p->accounts_service_sound_proxy != NULL)
372+ && dbus_accounts_service_sound_get_silent_mode(p->accounts_service_sound_proxy);
373+}
374+
375+static void
376+play_low_battery_sound (IndicatorPowerNotifier * self)
377+{
378+ const gchar * const key = LOW_BATTERY_SOUND;
379+ gchar * filename;
380+ priv_t * const p = get_priv(self);
381+
382+ /* can't play? */
383+ g_return_if_fail (p->sound_player != NULL);
384+
385+ /* won't play? */
386+ if (silent_mode(self))
387+ return;
388+
389+ filename = datafile_find(DATAFILE_TYPE_SOUND, key);
390+ if (filename != NULL)
391+ {
392+ gchar * uri = g_filename_to_uri(filename, NULL, NULL);
393+ indicator_power_sound_player_play_uri (p->sound_player, uri);
394+ g_free(uri);
395+ g_free(filename);
396+ }
397+ else
398+ {
399+ g_warning("Unable to find '%s' in XDG data dirs", key);
400+ }
401+}
402+
403+/***
404 **** Notifications
405 ***/
406
407@@ -300,6 +387,7 @@
408 ((new_power_level != POWER_LEVEL_OK) && new_discharging && !old_discharging))
409 {
410 notification_show (self);
411+ play_low_battery_sound (self);
412 }
413 else if (!new_discharging || (new_power_level == POWER_LEVEL_OK))
414 {
415@@ -330,6 +418,10 @@
416 g_value_set_object (value, p->battery);
417 break;
418
419+ case PROP_SOUND_PLAYER:
420+ g_value_set_object (value, p->sound_player);
421+ break;
422+
423 default:
424 G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
425 }
426@@ -349,6 +441,10 @@
427 indicator_power_notifier_set_battery (self, g_value_get_object(value));
428 break;
429
430+ case PROP_SOUND_PLAYER:
431+ indicator_power_notifier_set_sound_player (self, g_value_get_object(value));
432+ break;
433+
434 default:
435 G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
436 }
437@@ -360,10 +456,18 @@
438 IndicatorPowerNotifier * const self = INDICATOR_POWER_NOTIFIER(o);
439 priv_t * const p = get_priv (self);
440
441+ if (p->cancellable != NULL)
442+ {
443+ g_cancellable_cancel(p->cancellable);
444+ g_clear_object(&p->cancellable);
445+ }
446+
447 indicator_power_notifier_set_bus (self, NULL);
448+ indicator_power_notifier_set_sound_player (self, NULL);
449 notification_clear (self);
450 indicator_power_notifier_set_battery (self, NULL);
451 g_clear_object (&p->dbus_battery);
452+ g_clear_object (&p->accounts_service_sound_proxy);
453
454 G_OBJECT_CLASS (indicator_power_notifier_parent_class)->dispose (o);
455 }
456@@ -382,7 +486,6 @@
457 **** Instantiation
458 ***/
459
460-
461 static void
462 indicator_power_notifier_init (IndicatorPowerNotifier * self)
463 {
464@@ -394,8 +497,22 @@
465
466 p->power_level = POWER_LEVEL_OK;
467
468+ p->cancellable = g_cancellable_new();
469+
470 if (!instance_count++ && !notify_init("indicator-power-service"))
471 g_critical("Unable to initialize libnotify! Notifications might not be shown.");
472+
473+ p->accounts_service_sound_proxy_pending = TRUE;
474+ gchar* object_path = g_strdup_printf("/org/freedesktop/Accounts/User%lu", (gulong)getuid());
475+ dbus_accounts_service_sound_proxy_new_for_bus(
476+ G_BUS_TYPE_SYSTEM,
477+ G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
478+ "org.freedesktop.Accounts",
479+ object_path,
480+ p->cancellable,
481+ on_sound_proxy_ready,
482+ self);
483+ g_clear_pointer(&object_path, g_free);
484 }
485
486 static void
487@@ -415,6 +532,13 @@
488 G_TYPE_OBJECT,
489 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
490
491+ properties[PROP_SOUND_PLAYER] = g_param_spec_object (
492+ PROP_SOUND_PLAYER_NAME,
493+ "Sound Player",
494+ "The current sound player",
495+ G_TYPE_OBJECT,
496+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
497+
498 g_object_class_install_properties (object_class, LAST_PROP, properties);
499 }
500
501@@ -423,9 +547,11 @@
502 ***/
503
504 IndicatorPowerNotifier *
505-indicator_power_notifier_new (void)
506+indicator_power_notifier_new (IndicatorPowerSoundPlayer * sound_player)
507 {
508- GObject * o = g_object_new (INDICATOR_TYPE_POWER_NOTIFIER, NULL);
509+ GObject * o = g_object_new (INDICATOR_TYPE_POWER_NOTIFIER,
510+ PROP_SOUND_PLAYER_NAME, sound_player,
511+ NULL);
512
513 return INDICATOR_POWER_NOTIFIER (o);
514 }
515@@ -465,6 +591,26 @@
516 }
517
518 void
519+indicator_power_notifier_set_sound_player (IndicatorPowerNotifier * self,
520+ IndicatorPowerSoundPlayer * sound_player)
521+{
522+ priv_t * p;
523+
524+ g_return_if_fail(INDICATOR_IS_POWER_NOTIFIER(self));
525+ g_return_if_fail((sound_player == NULL) || INDICATOR_IS_POWER_SOUND_PLAYER(sound_player));
526+
527+ p = get_priv (self);
528+
529+ if (p->sound_player == sound_player)
530+ return;
531+
532+ g_clear_object(&p->sound_player);
533+
534+ if (sound_player != NULL)
535+ p->sound_player = g_object_ref(sound_player);
536+}
537+
538+void
539 indicator_power_notifier_set_bus (IndicatorPowerNotifier * self,
540 GDBusConnection * bus)
541 {
542
543=== modified file 'src/notifier.h'
544--- src/notifier.h 2014-07-25 04:31:11 +0000
545+++ src/notifier.h 2016-01-04 20:26:17 +0000
546@@ -1,5 +1,5 @@
547 /*
548- * Copyright 2014 Canonical Ltd.
549+ * Copyright 2014-2016 Canonical Ltd.
550 *
551 * This program is free software: you can redistribute it and/or modify it
552 * under the terms of the GNU General Public License version 3, as published
553@@ -23,6 +23,7 @@
554 #include <gio/gio.h>
555
556 #include "device.h"
557+#include "sound-player.h"
558
559 G_BEGIN_DECLS
560
561@@ -55,7 +56,7 @@
562
563 GType indicator_power_notifier_get_type (void);
564
565-IndicatorPowerNotifier * indicator_power_notifier_new (void);
566+IndicatorPowerNotifier * indicator_power_notifier_new (IndicatorPowerSoundPlayer * sound_player);
567
568 void indicator_power_notifier_set_bus (IndicatorPowerNotifier * self,
569 GDBusConnection * connection);
570@@ -63,6 +64,9 @@
571 void indicator_power_notifier_set_battery (IndicatorPowerNotifier * self,
572 IndicatorPowerDevice * battery);
573
574+void indicator_power_notifier_set_sound_player (IndicatorPowerNotifier * self,
575+ IndicatorPowerSoundPlayer * battery);
576+
577 #define POWER_LEVEL_STR_OK "ok"
578 #define POWER_LEVEL_STR_LOW "low"
579 #define POWER_LEVEL_STR_VERY_LOW "very_low"
580
581=== modified file 'src/service.c'
582--- src/service.c 2015-08-27 14:18:40 +0000
583+++ src/service.c 2016-01-04 20:26:17 +0000
584@@ -1,9 +1,5 @@
585 /*
586- * Copyright 2013 Canonical Ltd.
587- *
588- * Authors:
589- * Charles Kerr <charles.kerr@canonical.com>
590- * Ted Gould <ted@canonical.com>
591+ * Copyright 2013-2016 Canonical Ltd.
592 *
593 * This program is free software: you can redistribute it and/or modify it
594 * under the terms of the GNU General Public License version 3, as published
595@@ -16,6 +12,10 @@
596 *
597 * You should have received a copy of the GNU General Public License along
598 * with this program. If not, see <http://www.gnu.org/licenses/>.
599+ *
600+ * Authors:
601+ * Charles Kerr <charles.kerr@canonical.com>
602+ * Ted Gould <ted@canonical.com>
603 */
604
605 #include <glib/gi18n.h>
606@@ -53,6 +53,7 @@
607 PROP_0,
608 PROP_BUS,
609 PROP_DEVICE_PROVIDER,
610+ PROP_NOTIFIER,
611 LAST_PROP
612 };
613
614@@ -952,7 +953,8 @@
615 g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_BUS]);
616
617 /* export the battery properties */
618- indicator_power_notifier_set_bus (p->notifier, connection);
619+ if (p->notifier != NULL)
620+ indicator_power_notifier_set_bus (p->notifier, connection);
621
622 /* export the actions */
623 if ((id = g_dbus_connection_export_action_group (connection,
624@@ -1094,6 +1096,10 @@
625 g_value_set_object (value, p->device_provider);
626 break;
627
628+ case PROP_NOTIFIER:
629+ g_value_set_object (value, p->notifier);
630+ break;
631+
632 default:
633 G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
634 }
635@@ -1113,6 +1119,10 @@
636 indicator_power_service_set_device_provider (self, g_value_get_object (value));
637 break;
638
639+ case PROP_NOTIFIER:
640+ indicator_power_service_set_notifier (self, g_value_get_object (value));
641+ break;
642+
643 default:
644 G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
645 }
646@@ -1155,6 +1165,7 @@
647 g_clear_object (&p->conn);
648
649 indicator_power_service_set_device_provider (self, NULL);
650+ indicator_power_service_set_notifier (self, NULL);
651
652 G_OBJECT_CLASS (indicator_power_service_parent_class)->dispose (o);
653 }
654@@ -1178,8 +1189,6 @@
655
656 p->settings = g_settings_new ("com.canonical.indicator.power");
657
658- p->notifier = indicator_power_notifier_new ();
659-
660 p->brightness = indicator_power_brightness_new();
661 g_signal_connect_swapped(p->brightness, "notify::percentage",
662 G_CALLBACK(update_brightness_action_state), self);
663@@ -1241,6 +1250,13 @@
664 G_TYPE_OBJECT,
665 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
666
667+ properties[PROP_NOTIFIER] = g_param_spec_object (
668+ "notifier",
669+ "Notifier",
670+ "Notifies user of important battery changes",
671+ G_TYPE_OBJECT,
672+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
673+
674 g_object_class_install_properties (object_class, LAST_PROP, properties);
675 }
676
677@@ -1249,10 +1265,12 @@
678 ***/
679
680 IndicatorPowerService *
681-indicator_power_service_new (IndicatorPowerDeviceProvider * device_provider)
682+indicator_power_service_new (IndicatorPowerDeviceProvider * device_provider,
683+ IndicatorPowerNotifier * notifier)
684 {
685 GObject * o = g_object_new (INDICATOR_TYPE_POWER_SERVICE,
686 "device-provider", device_provider,
687+ "notifier", notifier,
688 NULL);
689
690 return INDICATOR_POWER_SERVICE (o);
691@@ -1291,6 +1309,29 @@
692 }
693 }
694
695+void
696+indicator_power_service_set_notifier (IndicatorPowerService * self,
697+ IndicatorPowerNotifier * notifier)
698+{
699+ priv_t * p;
700+
701+ g_return_if_fail (INDICATOR_IS_POWER_SERVICE (self));
702+ g_return_if_fail (!notifier || INDICATOR_IS_POWER_NOTIFIER (notifier));
703+ p = self->priv;
704+
705+ if (p->notifier == notifier)
706+ return;
707+
708+ g_clear_object (&p->notifier);
709+
710+ if (notifier != NULL)
711+ {
712+ p->notifier = g_object_ref (notifier);
713+ indicator_power_notifier_set_bus (p->notifier, p->conn);
714+ }
715+}
716+
717+
718 /* If a device has multiple batteries and uses only one of them at a time,
719 they should be presented as separate items inside the battery menu,
720 but everywhere else they should be aggregated (bug 880881).
721
722=== modified file 'src/service.h'
723--- src/service.h 2013-06-19 15:10:50 +0000
724+++ src/service.h 2016-01-04 20:26:17 +0000
725@@ -24,6 +24,7 @@
726 #include <glib-object.h>
727
728 #include "device-provider.h"
729+#include "notifier.h"
730
731 G_BEGIN_DECLS
732
733@@ -64,11 +65,15 @@
734
735 GType indicator_power_service_get_type (void);
736
737-IndicatorPowerService * indicator_power_service_new (IndicatorPowerDeviceProvider * provider);
738+IndicatorPowerService * indicator_power_service_new (IndicatorPowerDeviceProvider * provider,
739+ IndicatorPowerNotifier * notifier);
740
741 void indicator_power_service_set_device_provider (IndicatorPowerService * self,
742 IndicatorPowerDeviceProvider * provider);
743
744+void indicator_power_service_set_notifier (IndicatorPowerService * self,
745+ IndicatorPowerNotifier * notifier);
746+
747 IndicatorPowerDevice * indicator_power_service_choose_primary_device (GList * devices);
748
749
750
751=== added file 'src/sound-player-gst.c'
752--- src/sound-player-gst.c 1970-01-01 00:00:00 +0000
753+++ src/sound-player-gst.c 2016-01-04 20:26:17 +0000
754@@ -0,0 +1,173 @@
755+/*
756+ * Copyright 2016 Canonical Ltd.
757+ *
758+ * This program is free software: you can redistribute it and/or modify it
759+ * under the terms of the GNU General Public License version 3, as published
760+ * by the Free Software Foundation.
761+ *
762+ * This program is distributed in the hope that it will be useful, but
763+ * WITHOUT ANY WARRANTY; without even the implied warranties of
764+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
765+ * PURPOSE. See the GNU General Public License for more details.
766+ *
767+ * You should have received a copy of the GNU General Public License along
768+ * with this program. If not, see <http://www.gnu.org/licenses/>.
769+ *
770+ * Authors:
771+ * Charles Kerr <charles.kerr@canonical.com>
772+ */
773+
774+#include "sound-player.h"
775+#include "sound-player-gst.h"
776+
777+#include <gst/gst.h>
778+
779+
780+/***
781+**** private struct
782+***/
783+
784+typedef struct
785+{
786+ int unused;
787+}
788+IndicatorPowerSoundPlayerGSTPrivate;
789+
790+typedef IndicatorPowerSoundPlayerGSTPrivate priv_t;
791+
792+#define get_priv(o) ((priv_t*)indicator_power_sound_player_gst_get_instance_private(o))
793+
794+
795+/***
796+**** GObject boilerplate
797+***/
798+
799+static void indicator_power_device_provider_interface_init (
800+ IndicatorPowerSoundPlayerInterface * iface);
801+
802+G_DEFINE_TYPE_WITH_CODE (
803+ IndicatorPowerSoundPlayerGST,
804+ indicator_power_sound_player_gst,
805+ G_TYPE_OBJECT,
806+ G_ADD_PRIVATE(IndicatorPowerSoundPlayerGST)
807+ G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_POWER_SOUND_PLAYER,
808+ indicator_power_device_provider_interface_init))
809+
810+/***
811+**** GSTREAMER
812+***/
813+
814+static void
815+gst_init_once(void)
816+{
817+ static gboolean gst_init_checked = FALSE;
818+
819+ if (G_UNLIKELY(!gst_init_checked))
820+ {
821+ GError* error = NULL;
822+ if (!gst_init_check(NULL, NULL, &error))
823+ {
824+ g_critical("Unable to play alarm sound: %s", error->message);
825+ g_error_free(error);
826+ }
827+ gst_init_checked = TRUE;
828+ }
829+}
830+
831+static gboolean bus_callback(GstBus* bus G_GNUC_UNUSED, GstMessage* msg, gpointer gelement)
832+{
833+ const GstMessageType message_type = GST_MESSAGE_TYPE(msg);
834+
835+ if (GST_MESSAGE_SRC(msg) != gelement)
836+ return G_SOURCE_CONTINUE;
837+
838+ /* on eos, cleanup the element and cancel our gst bus subscription */
839+ if (message_type == GST_MESSAGE_EOS)
840+ {
841+ g_debug("got GST_MESSAGE_EOS on sound play");
842+ gst_element_set_state(GST_ELEMENT(gelement), GST_STATE_NULL);
843+ gst_object_unref(gelement);
844+ return G_SOURCE_REMOVE;
845+ }
846+
847+ /* on stream start, set the media role to 'alert' if we're using pulsesink */
848+ if (message_type == GST_MESSAGE_STREAM_START)
849+ {
850+ GstElement* audio_sink = NULL;
851+ g_debug("got GST_MESSAGE_STREAM_START on sound play");
852+ g_object_get(gelement, "audio-sink", &audio_sink, NULL);
853+ if (audio_sink != NULL)
854+ {
855+ GstPluginFeature* feature;
856+ feature = GST_PLUGIN_FEATURE_CAST(GST_ELEMENT_GET_CLASS(audio_sink)->elementfactory);
857+ if (feature && g_strcmp0(gst_plugin_feature_get_name(feature), "pulsesink") == 0)
858+ {
859+ const gchar* const props_str = "props,media.role=alert";
860+ GstStructure* props = gst_structure_from_string(props_str, NULL);
861+ g_debug("setting audio sink properties to '%s'", props_str);
862+ g_object_set(audio_sink, "stream-properties", props, NULL);
863+ g_clear_pointer(&props, gst_structure_free);
864+ }
865+ gst_object_unref(audio_sink);
866+ }
867+ }
868+
869+ return G_SOURCE_CONTINUE;
870+}
871+
872+/***
873+**** IndicatorPowerSoundPlayer virtual functions
874+***/
875+
876+static void
877+my_play_uri (IndicatorPowerSoundPlayer * self G_GNUC_UNUSED, const gchar * uri)
878+{
879+ GstElement * element;
880+ GstBus * bus;
881+
882+ /* create the element */
883+ element = gst_element_factory_make("playbin", NULL);
884+
885+ /* start listening for gst events */
886+ bus = gst_pipeline_get_bus(GST_PIPELINE(element));
887+ gst_bus_add_watch(bus, bus_callback, element);
888+ gst_object_unref(bus);
889+
890+ /* play the sound */
891+ g_debug("Playing '%s'", uri);
892+ g_object_set(element, "uri", uri, NULL);
893+ gst_element_set_state(element, GST_STATE_PLAYING);
894+}
895+
896+/***
897+**** Instantiation
898+***/
899+
900+static void
901+indicator_power_sound_player_gst_class_init (IndicatorPowerSoundPlayerGSTClass * klass G_GNUC_UNUSED)
902+{
903+ gst_init_once();
904+}
905+
906+static void
907+indicator_power_device_provider_interface_init (IndicatorPowerSoundPlayerInterface * iface)
908+{
909+ iface->play_uri = my_play_uri;
910+}
911+
912+static void
913+indicator_power_sound_player_gst_init (IndicatorPowerSoundPlayerGST * self G_GNUC_UNUSED)
914+{
915+}
916+
917+/***
918+**** Public API
919+***/
920+
921+IndicatorPowerSoundPlayer *
922+indicator_power_sound_player_gst_new(void)
923+{
924+ gpointer o = g_object_new (INDICATOR_TYPE_POWER_SOUND_PLAYER_GST, NULL);
925+
926+ return INDICATOR_POWER_SOUND_PLAYER (o);
927+}
928
929=== added file 'src/sound-player-gst.h'
930--- src/sound-player-gst.h 1970-01-01 00:00:00 +0000
931+++ src/sound-player-gst.h 2016-01-04 20:26:17 +0000
932@@ -0,0 +1,70 @@
933+/*
934+ * Copyright 2016 Canonical Ltd.
935+ *
936+ * This program is free software: you can redistribute it and/or modify it
937+ * under the terms of the GNU General Public License version 3, as published
938+ * by the Free Software Foundation.
939+ *
940+ * This program is distributed in the hope that it will be useful, but
941+ * WITHOUT ANY WARRANTY; without even the implied warranties of
942+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
943+ * PURPOSE. See the GNU General Public License for more details.
944+ *
945+ * You should have received a copy of the GNU General Public License along
946+ * with this program. If not, see <http://www.gnu.org/licenses/>.
947+ *
948+ * Authors:
949+ * Charles Kerr <charles.kerr@canonical.com>
950+ */
951+
952+#ifndef __INDICATOR_POWER_SOUND_PLAYER_GST__H__
953+#define __INDICATOR_POWER_SOUND_PLAYER_GST__H__
954+
955+#include <glib-object.h> /* parent class */
956+
957+#include "device-provider.h"
958+
959+G_BEGIN_DECLS
960+
961+#define INDICATOR_TYPE_POWER_SOUND_PLAYER_GST \
962+ (indicator_power_sound_player_gst_get_type())
963+
964+#define INDICATOR_POWER_SOUND_PLAYER_GST(o) \
965+ (G_TYPE_CHECK_INSTANCE_CAST ((o), \
966+ INDICATOR_TYPE_POWER_SOUND_PLAYER_GST, \
967+ IndicatorPowerSoundPlayerGST))
968+
969+#define INDICATOR_POWER_SOUND_PLAYER_GST_GET_CLASS(o) \
970+ (G_TYPE_INSTANCE_GET_CLASS ((o), \
971+ INDICATOR_TYPE_POWER_SOUND_PLAYER_GST, \
972+ IndicatorPowerSoundPlayerGSTClass))
973+
974+#define INDICATOR_IS_POWER_SOUND_PLAYER_GST(o) \
975+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
976+ INDICATOR_TYPE_POWER_SOUND_PLAYER_GST))
977+
978+typedef struct _IndicatorPowerSoundPlayerGST
979+ IndicatorPowerSoundPlayerGST;
980+typedef struct _IndicatorPowerSoundPlayerGSTClass
981+ IndicatorPowerSoundPlayerGSTClass;
982+
983+/**
984+ * An IndicatorPowerSoundPlayer which gets its devices from GST.
985+ */
986+struct _IndicatorPowerSoundPlayerGST
987+{
988+ GObject parent_instance;
989+};
990+
991+struct _IndicatorPowerSoundPlayerGSTClass
992+{
993+ GObjectClass parent_class;
994+};
995+
996+GType indicator_power_sound_player_gst_get_type (void);
997+
998+IndicatorPowerSoundPlayer * indicator_power_sound_player_gst_new (void);
999+
1000+G_END_DECLS
1001+
1002+#endif /* __INDICATOR_POWER_SOUND_PLAYER_GST__H__ */
1003
1004=== added file 'src/sound-player.c'
1005--- src/sound-player.c 1970-01-01 00:00:00 +0000
1006+++ src/sound-player.c 2016-01-04 20:26:17 +0000
1007@@ -0,0 +1,45 @@
1008+/*
1009+ * Copyright 2016 Canonical Ltd.
1010+ *
1011+ * This program is free software: you can redistribute it and/or modify it
1012+ * under the terms of the GNU General Public License version 3, as published
1013+ * by the Free Software Foundation.
1014+ *
1015+ * This program is distributed in the hope that it will be useful, but
1016+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1017+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1018+ * PURPOSE. See the GNU General Public License for more details.
1019+ *
1020+ * You should have received a copy of the GNU General Public License along
1021+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1022+ *
1023+ * Authors:
1024+ * Charles Kerr <charles.kerr@canonical.com>
1025+ */
1026+
1027+#include "sound-player.h"
1028+
1029+G_DEFINE_INTERFACE (IndicatorPowerSoundPlayer,
1030+ indicator_power_sound_player,
1031+ 0)
1032+
1033+static void
1034+indicator_power_sound_player_default_init (IndicatorPowerSoundPlayerInterface * klass G_GNUC_UNUSED)
1035+{
1036+}
1037+
1038+/***
1039+**** PUBLIC API
1040+***/
1041+
1042+void
1043+indicator_power_sound_player_play_uri (IndicatorPowerSoundPlayer * self,
1044+ const gchar * uri)
1045+{
1046+ IndicatorPowerSoundPlayerInterface * iface;
1047+
1048+ g_return_if_fail (INDICATOR_IS_POWER_SOUND_PLAYER (self));
1049+ iface = INDICATOR_POWER_SOUND_PLAYER_GET_INTERFACE (self);
1050+ g_return_if_fail (iface->play_uri != NULL);
1051+ iface->play_uri (self, uri);
1052+}
1053
1054=== added file 'src/sound-player.h'
1055--- src/sound-player.h 1970-01-01 00:00:00 +0000
1056+++ src/sound-player.h 2016-01-04 20:26:17 +0000
1057@@ -0,0 +1,72 @@
1058+/*
1059+ * Copyright 2016 Canonical Ltd.
1060+ *
1061+ * This program is free software: you can redistribute it and/or modify it
1062+ * under the terms of the GNU General Public License version 3, as published
1063+ * by the Free Software Foundation.
1064+ *
1065+ * This program is distributed in the hope that it will be useful, but
1066+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1067+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1068+ * PURPOSE. See the GNU General Public License for more details.
1069+ *
1070+ * You should have received a copy of the GNU General Public License along
1071+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1072+ *
1073+ * Authors:
1074+ * Charles Kerr <charles.kerr@canonical.com>
1075+ */
1076+
1077+#ifndef __INDICATOR_POWER_SOUND_PLAYER__H__
1078+#define __INDICATOR_POWER_SOUND_PLAYER__H__
1079+
1080+#include <glib-object.h>
1081+
1082+G_BEGIN_DECLS
1083+
1084+#define INDICATOR_TYPE_POWER_SOUND_PLAYER \
1085+ (indicator_power_sound_player_get_type ())
1086+
1087+#define INDICATOR_POWER_SOUND_PLAYER(obj) \
1088+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
1089+ INDICATOR_TYPE_POWER_SOUND_PLAYER, \
1090+ IndicatorPowerSoundPlayer))
1091+
1092+#define INDICATOR_IS_POWER_SOUND_PLAYER(obj) \
1093+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_POWER_SOUND_PLAYER))
1094+
1095+#define INDICATOR_POWER_SOUND_PLAYER_GET_INTERFACE(inst) \
1096+ (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
1097+ INDICATOR_TYPE_POWER_SOUND_PLAYER, \
1098+ IndicatorPowerSoundPlayerInterface))
1099+
1100+typedef struct _IndicatorPowerSoundPlayer
1101+ IndicatorPowerSoundPlayer;
1102+
1103+typedef struct _IndicatorPowerSoundPlayerInterface
1104+ IndicatorPowerSoundPlayerInterface;
1105+
1106+/**
1107+ * An interface class for an object that plays sounds.
1108+ */
1109+struct _IndicatorPowerSoundPlayerInterface
1110+{
1111+ GTypeInterface parent_iface;
1112+
1113+ /* virtual functions */
1114+ void (*play_uri) (IndicatorPowerSoundPlayer * self,
1115+ const gchar * uri);
1116+};
1117+
1118+GType indicator_power_sound_player_get_type (void);
1119+
1120+/***
1121+****
1122+***/
1123+
1124+void indicator_power_sound_player_play_uri (IndicatorPowerSoundPlayer * self,
1125+ const gchar * uri);
1126+
1127+G_END_DECLS
1128+
1129+#endif /* __INDICATOR_POWER_SOUND_PLAYER__H__ */
1130
1131=== modified file 'tests/CMakeLists.txt'
1132--- tests/CMakeLists.txt 2014-10-10 21:11:36 +0000
1133+++ tests/CMakeLists.txt 2016-01-04 20:26:17 +0000
1134@@ -14,11 +14,23 @@
1135 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${C_WARNING_ARGS}")
1136 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-weak-vtables -Wno-global-constructors") # Google Test
1137
1138+# build the mocks
1139+set(MOCK_LIB "indicatorpowerservicemocks")
1140+set(MOCK_SOURCES sound-player-mock.c)
1141+set_source_files_properties(${MOCK_SOURCES}
1142+ PROPERTIES COMPILE_FLAGS "${C_WARNING_ARGS} -g -std=c99")
1143+add_library(${MOCK_LIB} STATIC ${MOCK_SOURCES})
1144+
1145 # build the necessary schemas
1146 set_directory_properties (PROPERTIES
1147 ADDITIONAL_MAKE_CLEAN_FILES gschemas.compiled)
1148 set_source_files_properties (gschemas.compiled GENERATED)
1149
1150+# make a XDG_DATA_HOME for sounds/
1151+set(XDG_DATA_HOME "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}")
1152+add_definitions(-DXDG_DATA_HOME="${XDG_DATA_HOME}")
1153+file(COPY "${CMAKE_SOURCE_DIR}/data/sounds" DESTINATION "${XDG_DATA_HOME}/${CMAKE_PROJECT_NAME}")
1154+
1155 # GSettings:
1156 # compile the indicator-power schema into a gschemas.compiled file in this directory,
1157 # and help the tests to find that file by setting -DSCHEMA_DIR
1158@@ -44,8 +56,8 @@
1159 set (TEST_NAME ${name})
1160 add_executable (${TEST_NAME} ${TEST_NAME}.cc gschemas.compiled)
1161 add_test (${TEST_NAME} ${TEST_NAME})
1162- add_dependencies (${TEST_NAME} libindicatorpowerservice)
1163- target_link_libraries (${TEST_NAME} indicatorpowerservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
1164+ add_dependencies (${TEST_NAME} ${MOCK_LIB} libindicatorpowerservice)
1165+ target_link_libraries (${TEST_NAME} ${MOCK_LIB} indicatorpowerservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
1166 endfunction()
1167 add_test_by_name(test-notify)
1168 add_test(NAME dear-reader-the-next-test-takes-80-seconds COMMAND true)
1169
1170=== modified file 'tests/glib-fixture.h'
1171--- tests/glib-fixture.h 2014-09-08 04:56:10 +0000
1172+++ tests/glib-fixture.h 2016-01-04 20:26:17 +0000
1173@@ -52,7 +52,7 @@
1174
1175 if (expected_log[level] != n)
1176 for (size_t i=0; i<n; ++i)
1177- g_print("%d %s\n", (n+1), v[i].c_str());
1178+ g_print("%d %s\n", int(n+1), v[i].c_str());
1179 }
1180
1181 expected_log.clear();
1182
1183=== added file 'tests/sound-player-mock.c'
1184--- tests/sound-player-mock.c 1970-01-01 00:00:00 +0000
1185+++ tests/sound-player-mock.c 2016-01-04 20:26:17 +0000
1186@@ -0,0 +1,94 @@
1187+/*
1188+ * Copyright 2016 Canonical Ltd.
1189+ *
1190+ * This program is free software: you can redistribute it and/or modify it
1191+ * under the terms of the GNU General Public License version 3, as published
1192+ * by the Free Software Foundation.
1193+ *
1194+ * This program is distributed in the hope that it will be useful, but
1195+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1196+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1197+ * PURPOSE. See the GNU General Public License for more details.
1198+ *
1199+ * You should have received a copy of the GNU General Public License along
1200+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1201+ *
1202+ * Authors:
1203+ * Charles Kerr <charles.kerr@canonical.com>
1204+ */
1205+
1206+#include "sound-player.h"
1207+#include "sound-player-mock.h"
1208+
1209+enum
1210+{
1211+ SIGNAL_URI_PLAYED,
1212+ LAST_SIGNAL
1213+};
1214+
1215+static guint signals[LAST_SIGNAL] = { 0 };
1216+
1217+/***
1218+**** GObject boilerplate
1219+***/
1220+
1221+static void indicator_power_sound_player_interface_init (
1222+ IndicatorPowerSoundPlayerInterface * iface);
1223+
1224+G_DEFINE_TYPE_WITH_CODE (
1225+ IndicatorPowerSoundPlayerMock,
1226+ indicator_power_sound_player_mock,
1227+ G_TYPE_OBJECT,
1228+ G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_POWER_SOUND_PLAYER,
1229+ indicator_power_sound_player_interface_init))
1230+
1231+/***
1232+**** IndicatorPowerSoundPlayer virtual functions
1233+***/
1234+
1235+static void
1236+my_play_uri (IndicatorPowerSoundPlayer * self, const gchar * uri)
1237+{
1238+ g_signal_emit (self, signals[SIGNAL_URI_PLAYED], 0, uri, NULL);
1239+}
1240+
1241+/***
1242+**** Instantiation
1243+***/
1244+
1245+static void
1246+indicator_power_sound_player_mock_class_init (IndicatorPowerSoundPlayerMockClass * klass G_GNUC_UNUSED)
1247+{
1248+ signals[SIGNAL_URI_PLAYED] = g_signal_new (
1249+ "uri-played",
1250+ G_TYPE_FROM_CLASS(klass),
1251+ G_SIGNAL_RUN_LAST,
1252+ G_STRUCT_OFFSET (IndicatorPowerSoundPlayerMockClass, uri_played),
1253+ NULL, NULL,
1254+ g_cclosure_marshal_VOID__STRING,
1255+ G_TYPE_NONE, 1, G_TYPE_STRING);
1256+}
1257+
1258+static void
1259+indicator_power_sound_player_interface_init (IndicatorPowerSoundPlayerInterface * iface)
1260+{
1261+ iface->play_uri = my_play_uri;
1262+}
1263+
1264+static void
1265+indicator_power_sound_player_mock_init (IndicatorPowerSoundPlayerMock * self G_GNUC_UNUSED)
1266+{
1267+}
1268+
1269+/***
1270+**** Public API
1271+***/
1272+
1273+IndicatorPowerSoundPlayer *
1274+indicator_power_sound_player_mock_new (void)
1275+{
1276+ gpointer o = g_object_new (INDICATOR_TYPE_POWER_SOUND_PLAYER_MOCK, NULL);
1277+
1278+ return INDICATOR_POWER_SOUND_PLAYER (o);
1279+}
1280+
1281
1282=== added file 'tests/sound-player-mock.h'
1283--- tests/sound-player-mock.h 1970-01-01 00:00:00 +0000
1284+++ tests/sound-player-mock.h 2016-01-04 20:26:17 +0000
1285@@ -0,0 +1,75 @@
1286+/*
1287+ * Copyright 2016 Canonical Ltd.
1288+ *
1289+ * This program is free software: you can redistribute it and/or modify it
1290+ * under the terms of the GNU General Public License version 3, as published
1291+ * by the Free Software Foundation.
1292+ *
1293+ * This program is distributed in the hope that it will be useful, but
1294+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1295+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1296+ * PURPOSE. See the GNU General Public License for more details.
1297+ *
1298+ * You should have received a copy of the GNU General Public License along
1299+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1300+ *
1301+ * Authors:
1302+ * Charles Kerr <charles.kerr@canonical.com>
1303+ */
1304+
1305+#ifndef __INDICATOR_POWER_SOUND_PLAYER_MOCK__H__
1306+#define __INDICATOR_POWER_SOUND_PLAYER_MOCK__H__
1307+
1308+#include <glib-object.h> /* parent class */
1309+
1310+#include "sound-player.h"
1311+
1312+G_BEGIN_DECLS
1313+
1314+#define INDICATOR_TYPE_POWER_SOUND_PLAYER_MOCK \
1315+ (indicator_power_sound_player_mock_get_type())
1316+
1317+#define INDICATOR_POWER_SOUND_PLAYER_MOCK(o) \
1318+ (G_TYPE_CHECK_INSTANCE_CAST ((o), \
1319+ INDICATOR_TYPE_POWER_SOUND_PLAYER_MOCK, \
1320+ IndicatorPowerSoundPlayerMock))
1321+
1322+#define INDICATOR_POWER_SOUND_PLAYER_MOCK_GET_CLASS(o) \
1323+ (G_TYPE_INSTANCE_GET_CLASS ((o), \
1324+ INDICATOR_TYPE_POWER_SOUND_PLAYER_MOCK, \
1325+ IndicatorPowerSoundPlayerMockClass))
1326+
1327+#define INDICATOR_IS_POWER_SOUND_PLAYER_MOCK(o) \
1328+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
1329+ INDICATOR_TYPE_POWER_SOUND_PLAYER_MOCK))
1330+
1331+typedef struct _IndicatorPowerSoundPlayerMock
1332+ IndicatorPowerSoundPlayerMock;
1333+typedef struct _IndicatorPowerSoundPlayerMockPriv
1334+ IndicatorPowerSoundPlayerMockPriv;
1335+typedef struct _IndicatorPowerSoundPlayerMockClass
1336+ IndicatorPowerSoundPlayerMockClass;
1337+
1338+/**
1339+ * An IndicatorPowerSoundPlayer which gets its devices from Mock.
1340+ */
1341+struct _IndicatorPowerSoundPlayerMock
1342+{
1343+ GObject parent_instance;
1344+};
1345+
1346+struct _IndicatorPowerSoundPlayerMockClass
1347+{
1348+ GObjectClass parent_class;
1349+
1350+ /* signals */
1351+ void (*uri_played) (IndicatorPowerSoundPlayer * self, const gchar* uri);
1352+};
1353+
1354+GType indicator_power_sound_player_mock_get_type (void);
1355+
1356+IndicatorPowerSoundPlayer * indicator_power_sound_player_mock_new (void);
1357+
1358+G_END_DECLS
1359+
1360+#endif /* __INDICATOR_POWER_SOUND_PLAYER_MOCK__H__ */
1361
1362=== modified file 'tests/test-notify.cc'
1363--- tests/test-notify.cc 2014-09-08 04:56:10 +0000
1364+++ tests/test-notify.cc 2016-01-04 20:26:17 +0000
1365@@ -1,5 +1,5 @@
1366 /*
1367- * Copyright 2014 Canonical Ltd.
1368+ * Copyright 2014-2016 Canonical Ltd.
1369 *
1370 * This program is free software: you can redistribute it and/or modify it
1371 * under the terms of the GNU General Public License version 3, as published
1372@@ -23,6 +23,7 @@
1373 #include "dbus-shared.h"
1374 #include "device.h"
1375 #include "notifier.h"
1376+#include "sound-player-mock.h"
1377
1378 #include <gtest/gtest.h>
1379
1380@@ -77,6 +78,8 @@
1381 {
1382 super::SetUp();
1383
1384+ g_setenv ("XDG_DATA_HOME", XDG_DATA_HOME, TRUE);
1385+
1386 // init DBusMock / dbus-test-runner
1387
1388 service = dbus_test_service_new(nullptr);
1389@@ -273,7 +276,8 @@
1390
1391 // set up a notifier and give it the battery so changing the battery's
1392 // charge should show up on the bus.
1393- auto notifier = indicator_power_notifier_new ();
1394+ auto sound_player = indicator_power_sound_player_mock_new ();
1395+ auto notifier = indicator_power_notifier_new (sound_player);
1396 indicator_power_notifier_set_battery (notifier, battery);
1397 indicator_power_notifier_set_bus (notifier, bus);
1398 wait_msec();
1399@@ -315,14 +319,23 @@
1400
1401 // cleanup
1402 g_dbus_connection_signal_unsubscribe (bus, sub_tag);
1403+ g_object_unref (battery);
1404 g_object_unref (notifier);
1405- g_object_unref (battery);
1406+ g_object_unref (sound_player);
1407 }
1408
1409 /***
1410 ****
1411 ***/
1412
1413+namespace
1414+{
1415+ static void on_uri_played(IndicatorPowerSoundPlayer*, const char* uri, gpointer glast_uri)
1416+ {
1417+ *static_cast<std::string*>(glast_uri) = uri;
1418+ }
1419+}
1420+
1421 TEST_F(NotifyFixture, EventsThatChangeNotifications)
1422 {
1423 // GetCapabilities returns an array containing 'actions', so that we'll
1424@@ -343,9 +356,18 @@
1425 UP_DEVICE_STATE_DISCHARGING,
1426 30);
1427
1428+ // the file we expect to play on a low battery notification...
1429+ const char* expected_file = XDG_DATA_HOME "/" GETTEXT_PACKAGE "/sounds/" LOW_BATTERY_SOUND;
1430+ char* tmp = g_filename_to_uri(expected_file, nullptr, nullptr);
1431+ const std::string low_power_uri {tmp};
1432+ g_clear_pointer(&tmp, g_free);
1433+
1434 // set up a notifier and give it the battery so changing the battery's
1435 // charge should show up on the bus.
1436- auto notifier = indicator_power_notifier_new ();
1437+ std::string last_uri;
1438+ auto sound_player = indicator_power_sound_player_mock_new ();
1439+ g_signal_connect(sound_player, "uri-played", G_CALLBACK(on_uri_played), &last_uri);
1440+ auto notifier = indicator_power_notifier_new (sound_player);
1441 indicator_power_notifier_set_battery (notifier, battery);
1442 indicator_power_notifier_set_bus (notifier, bus);
1443 ChangedParams changed_params;
1444@@ -363,6 +385,7 @@
1445 // test setup case
1446 wait_msec();
1447 EXPECT_STREQ (POWER_LEVEL_STR_OK, changed_params.power_level.c_str());
1448+ EXPECT_TRUE(last_uri.empty());
1449
1450 // change the percent past the 'low' threshold and confirm that
1451 // a) the power level changes
1452@@ -373,38 +396,48 @@
1453 EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields);
1454 EXPECT_EQ (indicator_power_notifier_get_power_level(battery), changed_params.power_level);
1455 EXPECT_TRUE (changed_params.is_warning);
1456+ EXPECT_EQ (low_power_uri, last_uri);
1457
1458 // now test that the warning changes if the level goes down even lower...
1459+ last_uri.clear();
1460 changed_params = ChangedParams();
1461 set_battery_percentage (battery, percent_very_low);
1462 wait_msec();
1463 EXPECT_EQ (FIELD_POWER_LEVEL, changed_params.fields);
1464 EXPECT_STREQ (POWER_LEVEL_STR_VERY_LOW, changed_params.power_level.c_str());
1465+ EXPECT_EQ (low_power_uri, last_uri);
1466
1467 // ...and that the warning is taken down if the battery is plugged back in...
1468+ last_uri.clear();
1469 changed_params = ChangedParams();
1470 g_object_set (battery, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, nullptr);
1471 wait_msec();
1472 EXPECT_EQ (FIELD_IS_WARNING, changed_params.fields);
1473 EXPECT_FALSE (changed_params.is_warning);
1474+ EXPECT_TRUE(last_uri.empty());
1475
1476 // ...and that it comes back if we unplug again...
1477+ last_uri.clear();
1478 changed_params = ChangedParams();
1479 g_object_set (battery, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, nullptr);
1480 wait_msec();
1481 EXPECT_EQ (FIELD_IS_WARNING, changed_params.fields);
1482 EXPECT_TRUE (changed_params.is_warning);
1483+ EXPECT_EQ (low_power_uri, last_uri);
1484
1485 // ...and that it's taken down if the power level is OK
1486+ last_uri.clear();
1487 changed_params = ChangedParams();
1488 set_battery_percentage (battery, percent_low+1);
1489 wait_msec();
1490 EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields);
1491 EXPECT_STREQ (POWER_LEVEL_STR_OK, changed_params.power_level.c_str());
1492 EXPECT_FALSE (changed_params.is_warning);
1493+ EXPECT_TRUE(last_uri.empty());
1494
1495 // cleanup
1496 g_dbus_connection_signal_unsubscribe (bus, sub_tag);
1497 g_object_unref (notifier);
1498 g_object_unref (battery);
1499+ g_object_unref (sound_player);
1500 }

Subscribers

People subscribed via source and target branches