Merge lp:~xavi-garcia-mena/indicator-sound/sync-vivid-wily into lp:indicator-sound/15.04

Proposed by Xavi Garcia
Status: Merged
Approved by: Xavi Garcia
Approved revision: 501
Merged at revision: 497
Proposed branch: lp:~xavi-garcia-mena/indicator-sound/sync-vivid-wily
Merge into: lp:indicator-sound/15.04
Diff against target: 1204 lines (+616/-182)
10 files modified
data/com.canonical.indicator.sound.gschema.xml (+63/-0)
debian/changelog (+42/-0)
src/service.vala (+180/-132)
src/volume-control-pulse.vala (+162/-15)
src/volume-control.vala (+13/-1)
tests/CMakeLists.txt (+1/-1)
tests/media-player-user.cc (+138/-22)
tests/notifications-test.cc (+8/-8)
tests/volume-control-mock.vala (+4/-2)
tests/volume-control-test.cc (+5/-1)
To merge this branch: bzr merge lp:~xavi-garcia-mena/indicator-sound/sync-vivid-wily
Reviewer Review Type Date Requested Status
Charles Kerr (community) Approve
Xavi Garcia Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+273230@code.launchpad.net

Commit message

Sync vivid and wily branches

Description of the change

Sync vivid and wily branches

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Xavi Garcia (xavi-garcia-mena) wrote :

Approving as it is just a merge of commits from wily.
Source code should be in sync now with wily.

review: Approve
502. By Xavi Garcia

fixed version number in changelog

Revision history for this message
Charles Kerr (charlesk) wrote :

:)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/com.canonical.indicator.sound.gschema.xml'
2--- data/com.canonical.indicator.sound.gschema.xml 2014-12-03 15:12:01 +0000
3+++ data/com.canonical.indicator.sound.gschema.xml 2015-10-13 13:18:26 +0000
4@@ -39,5 +39,68 @@
5 Whether or not to show the sound indicator in the menu bar.
6 </description>
7 </key>
8+
9+ <!-- VOLUME -->
10+
11+ <key name="warning-volume-enabled" type="b">
12+ <default>true</default>
13+ <summary>Whether or not to show high volume warnings.</summary>
14+ <description>
15+ If enabled on a device, a confirmation dialog will be presented to the user if
16+ (a) something is plugged into the headphone jack (ie, no warnings for speaker volumes) AND
17+ (b) media is playing (ie, no warnings for ringtone volumes) AND
18+ (c) the user attempts to set the volume higher than warning-volume-decibels AND
19+ (d) the user has not indicated approval in the last warning-volume-approval-ttl seconds.
20+ </description>
21+ </key>
22+ <key name="warning-volume-confirmation-ttl" type="i">
23+ <default>72000</default>
24+ <summary>How many seconds a user's warning-volume approval should be remembered.</summary>
25+ <description>
26+ How long to remember a user's approval of the confirmation dialog discussed in the
27+ description of 'warning-volume-enabled'.
28+
29+ The default value (72,000 seconds) corresponds to the 20 hours suggested by
30+ EU standard EN 60950-1/Al2: “The acknowledgement does not need to be repeated
31+ more than once every 20 h of cumulative listening time.”
32+ </description>
33+ </key>
34+ <key name="warning-volume-decibels" type="d">
35+ <default>-8.0</default>
36+ <summary>Volume level that triggers a high volume warning.</summary>
37+ <description>
38+ Volume level that triggers a high volume warning.
39+ See warning-volume-enabled for details.
40+ </description>
41+ </key>
42+
43+ <key name="normal-volume-decibels" type="d">
44+ <default>0</default>
45+ <summary>Normal output volume.</summary>
46+ <description>
47+ The maximum volume when com.ubuntu.sound's 'allow-amplified-volume' setting is disabled.
48+
49+ To conform with EU standard EN 60950-1/Al2, this value should never be
50+ set to a dB that causes headphone sound output to exceed 100 dBA, nor
51+ electric output to exceed 150 mV.
52+
53+ The default value (0) corresponds to PulseAudio's PA_VOLUME_NORM.
54+ </description>
55+ </key>
56+
57+ <key name="amplified-volume-decibels" type="d">
58+ <default>11</default>
59+ <summary>Output volume to use when com.ubuntu.sound's 'allow-amplified-volume' setting is enabled.</summary>
60+ <description>
61+ The maximum volume when com.ubuntu.sound's 'allow-amplified-volume' setting is enabled.
62+
63+ To conform with EU standard EN 60950-1/Al2, this value should never be
64+ set to a dB that causes headphone sound output to exceed 100 dBA, nor
65+ electric output to exceed 150 mV.
66+
67+ The default value (11) corresponds to PulseAudio's PA_VOLUME_UI_MAX.
68+ </description>
69+ </key>
70+
71 </schema>
72 </schemalist>
73
74=== modified file 'debian/changelog'
75--- debian/changelog 2015-05-08 12:20:07 +0000
76+++ debian/changelog 2015-10-13 13:18:26 +0000
77@@ -1,3 +1,45 @@
78+indicator-sound (12.10.2+15.04.20150812.3-0ubuntu1) vivid; urgency=medium
79+
80+ [ CI Train Bot ]
81+ * New rebuild forced.
82+
83+ [ Charles Kerr ]
84+ * When showing a "Loud volumes can damage your hearing" confirmation
85+ warning, clamp the volume until the user hits "OK". (LP: #1481913)
86+
87+ -- CI Train Bot <ci-train-bot@canonical.com> Wed, 12 Aug 2015 20:55:05 +0000
88+
89+indicator-sound (12.10.2+15.04.20150807.6-0ubuntu1) vivid; urgency=medium
90+
91+ [ CI Train Bot ]
92+ * New rebuild forced.
93+
94+ [ Charles Kerr ]
95+ * Revised UI volume warnings to comply with EU requirements. (LP:
96+ #1481913)
97+
98+ -- CI Train Bot <ci-train-bot@canonical.com> Fri, 07 Aug 2015 22:35:58 +0000
99+
100+indicator-sound (12.10.2+15.04.20150605-0ubuntu1) vivid; urgency=medium
101+
102+ *
103+
104+ -- CI Train Bot <ci-train-bot@canonical.com> Fri, 05 Jun 2015 19:50:06 +0000
105+
106+indicator-sound (12.10.2+15.04.20150507+eventually4-0ubuntu1) vivid; urgency=medium
107+
108+ * Using eventually to avoid arbitrary timeouts in tests
109+
110+ -- Ted Gould <ted@ubuntu.com> Wed, 27 May 2015 11:11:19 -0500
111+
112+indicator-sound (12.10.2+15.04.20150507-0ubuntu1) vivid; urgency=medium
113+
114+ [ Charles Kerr ]
115+ * Use the BusWatcher to look for org.freedesktop.Notifications
116+ ownership changes on the bus. (LP: #1432446)
117+
118+ -- CI Train Bot <ci-train-bot@canonical.com> Thu, 07 May 2015 15:27:00 +0000
119+
120 indicator-sound (12.10.2+15.04.20150508-0ubuntu1) vivid; urgency=medium
121
122 [ CI Train Bot ]
123
124=== modified file 'src/service.vala'
125--- src/service.vala 2015-04-20 21:02:32 +0000
126+++ src/service.vala 2015-10-13 13:18:26 +0000
127@@ -20,6 +20,13 @@
128 public class IndicatorSound.Service: Object {
129 DBusConnection bus;
130
131+ /**
132+ * A copy of volume_control.volume made before just warn_notification
133+ * is shown. Since the volume is clamped during the warning, we cache
134+ * the previous volume to use iff the user hits "OK".
135+ */
136+ VolumeControl.Volume _pre_warn_volume = null;
137+
138 public Service (MediaPlayerList playerlist, VolumeControl volume, AccountsServiceUser? accounts) {
139 try {
140 bus = Bus.get_sync(GLib.BusType.SESSION);
141@@ -27,14 +34,19 @@
142 error("Unable to get DBus session bus: %s", e.message);
143 }
144
145- sync_notification = new Notify.Notification(_("Volume"), "", "audio-volume-muted");
146+ info_notification = new Notify.Notification(_("Volume"), "", "audio-volume-muted");
147+
148+ warn_notification = new Notify.Notification(_("Volume"), _("High volume can damage your hearing."), "audio-volume-high");
149+ warn_notification.set_hint ("x-canonical-non-shaped-icon", "true");
150+ warn_notification.set_hint ("x-canonical-snap-decisions", "true");
151+ warn_notification.set_hint ("x-canonical-private-affirmative-tint", "true");
152+ warn_notification.closed.connect((n) => { n.clear_actions(); });
153 BusWatcher.watch_namespace (GLib.BusType.SESSION,
154 "org.freedesktop.Notifications",
155- () => { debug("Notifications name appeared"); check_sync_notification = false; },
156- () => { debug("Notifications name vanshed"); check_sync_notification = false; });
157+ () => { debug("Notifications name appeared"); notify_server_caps_checked = false; },
158+ () => { debug("Notifications name vanshed"); notify_server_caps_checked = false; });
159
160 this.settings = new Settings ("com.canonical.indicator.sound");
161- this.sharedsettings = new Settings ("com.ubuntu.sound");
162
163 this.settings.bind ("visible", this, "visible", SettingsBindFlags.GET);
164 this.notify["visible"].connect ( () => this.update_root_icon () );
165@@ -83,19 +95,13 @@
166 this.sync_preferred_players ();
167 });
168
169- sharedsettings.bind ("allow-amplified-volume", this, "allow-amplified-volume", SettingsBindFlags.GET);
170-
171 /* Hide the notification when the menu is shown */
172 var shown_action = actions.lookup_action ("indicator-shown") as SimpleAction;
173 shown_action.change_state.connect ((state) => {
174- block_notifications = state.get_boolean();
175- if (block_notifications) {
176+ block_info_notifications = state.get_boolean();
177+ if (block_info_notifications) {
178 debug("Indicator is shown");
179- try {
180- sync_notification.close();
181- } catch (Error e) {
182- warning("Unable to close synchronous volume notification: %s", e.message);
183- }
184+ close_notification(info_notification);
185 } else {
186 debug("Indicator is hidden");
187 }
188@@ -111,11 +117,33 @@
189 this.menus.@foreach ( (profile, menu) => menu.export (bus, @"/com/canonical/indicator/sound/$profile"));
190 }
191
192+ private void close_notification(Notify.Notification? n) {
193+ return_if_fail (n != null);
194+ if (n.id != 0) {
195+ try {
196+ n.close();
197+ } catch (GLib.Error e) {
198+ warning("Unable to close notification: %s", e.message);
199+ }
200+ }
201+ }
202+
203+ private void show_notification(Notify.Notification? n) {
204+ return_if_fail (n != null);
205+ try {
206+ n.show ();
207+ } catch (GLib.Error e) {
208+ warning ("Unable to show notification: %s", e.message);
209+ }
210+ }
211+
212 ~Service() {
213 debug("Destroying Service Object");
214
215 clear_acts_player();
216
217+ stop_clamp_to_high_timeout();
218+
219 if (this.player_action_update_id > 0) {
220 Source.remove (this.player_action_update_id);
221 this.player_action_update_id = 0;
222@@ -145,28 +173,6 @@
223
224 public bool visible { get; set; }
225
226- public bool allow_amplified_volume {
227- get {
228- return this.max_volume > 1.0;
229- }
230-
231- set {
232- if (this.allow_amplified_volume == value)
233- return;
234-
235- if (value) {
236- /* from pulse/volume.h: #define PA_VOLUME_UI_MAX (pa_sw_volume_from_dB(+11.0)) */
237- this.max_volume = (double)PulseAudio.Volume.sw_from_dB(11.0) / PulseAudio.Volume.NORM;
238- }
239- else {
240- this.max_volume = 1.0;
241- }
242-
243- /* Normalize volume, because the volume action's state is [0.0, 1.0], see create_volume_action() */
244- this.actions.change_action_state ("volume", this.volume_control.volume.volume / this.max_volume);
245- }
246- }
247-
248 const ActionEntry[] action_entries = {
249 { "root", null, null, "@a{sv} {}", null },
250 { "scroll", activate_scroll_action, "i", null, null },
251@@ -178,7 +184,6 @@
252 SimpleActionGroup actions;
253 HashTable<string, SoundMenu> menus;
254 Settings settings;
255- Settings sharedsettings;
256 VolumeControl volume_control;
257 MediaPlayerList players;
258 uint player_action_update_id;
259@@ -187,28 +192,27 @@
260 bool syncing_preferred_players = false;
261 AccountsServiceUser? accounts_service = null;
262 bool export_to_accounts_service = false;
263- private Notify.Notification sync_notification;
264-
265- /* Maximum volume as a scaling factor between the volume action's state and the value in
266- * this.volume_control. See create_volume_action().
267- */
268- double max_volume = 1.0;
269+ private Notify.Notification info_notification;
270+ private Notify.Notification warn_notification;
271
272 const double volume_step_percentage = 0.06;
273
274- void activate_scroll_action (SimpleAction action, Variant? param) {
275+ private void activate_scroll_action (SimpleAction action, Variant? param) {
276 int delta = param.get_int32(); /* positive for up, negative for down */
277-
278- var scrollvol = new VolumeControl.Volume();
279- double v = this.volume_control.volume.volume + volume_step_percentage * delta;
280- scrollvol.volume = v.clamp (0.0, this.max_volume);
281- scrollvol.reason = VolumeControl.VolumeReasons.USER_KEYPRESS;
282- this.volume_control.volume = scrollvol;
283+ double v = volume_control.volume.volume + volume_step_percentage * delta;
284+ volume_control.set_volume_clamp (v, VolumeControl.VolumeReasons.USER_KEYPRESS);
285 }
286
287 void activate_desktop_settings (SimpleAction action, Variant? param) {
288 var env = Environment.get_variable ("DESKTOP_SESSION");
289 string cmd;
290+
291+ if (Environment.get_variable ("MIR_SOCKET") != null)
292+ {
293+ UrlDispatch.send ("settings:///system/sound");
294+ return;
295+ }
296+
297 if (env == "xubuntu" || env == "ubuntustudio")
298 cmd = "pavucontrol";
299 else if (env == "mate")
300@@ -242,12 +246,10 @@
301 void update_root_icon () {
302 double volume = this.volume_control.volume.volume;
303 string icon;
304- if (this.volume_control.mute)
305+ if (this.volume_control.mute || volume <= 0.0)
306 icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel";
307 else if (this.accounts_service != null && this.accounts_service.silentMode)
308 icon = "audio-volume-muted-panel";
309- else if (volume <= 0.0)
310- icon = "audio-volume-low-zero-panel";
311 else if (volume <= 0.3)
312 icon = "audio-volume-low-panel";
313 else if (volume <= 0.7)
314@@ -275,60 +277,83 @@
315 root_action.set_state (builder.end());
316 }
317
318- private bool check_sync_notification = false;
319- private bool support_sync_notification = false;
320- private bool block_notifications = false;
321-
322- void update_sync_notification () {
323- if (!check_sync_notification) {
324- support_sync_notification = false;
325+ private bool notify_server_caps_checked = false;
326+ private bool notify_server_supports_actions = false;
327+ private bool notify_server_supports_sync = false;
328+ private bool block_info_notifications = false;
329+
330+ private void update_notification () {
331+
332+ if (!notify_server_caps_checked) {
333 List<string> caps = Notify.get_server_caps ();
334- if (caps.find_custom ("x-canonical-private-synchronous", strcmp) != null) {
335- support_sync_notification = true;
336- }
337- check_sync_notification = true;
338+ notify_server_supports_actions = caps.find_custom ("actions", strcmp) != null;
339+ notify_server_supports_sync = caps.find_custom ("x-canonical-private-synchronous", strcmp) != null;
340+ notify_server_caps_checked = true;
341 }
342
343- if (!support_sync_notification)
344- return;
345-
346- if (block_notifications)
347- return;
348-
349- /* Determine Label */
350- string volume_label = "";
351- if (volume_control.high_volume)
352- volume_label = _("High volume");
353-
354- /* Choose an icon */
355- string icon = "audio-volume-muted";
356- if (volume_control.volume.volume <= 0.0)
357- icon = "audio-volume-muted";
358- else if (volume_control.volume.volume <= 0.3)
359- icon = "audio-volume-low";
360- else if (volume_control.volume.volume <= 0.7)
361- icon = "audio-volume-medium";
362- else
363- icon = "audio-volume-high";
364-
365- /* Check tint */
366- string tint = "false";
367- if (volume_control.high_volume)
368- tint = "true";
369-
370- /* Put it all into the notification */
371- sync_notification.clear_hints ();
372- sync_notification.update (_("Volume"), volume_label, icon);
373- sync_notification.set_hint ("value", (int32)Math.round(volume_control.volume.volume / this.max_volume * 100.0));
374- sync_notification.set_hint ("x-canonical-value-bar-tint", tint);
375- sync_notification.set_hint ("x-canonical-private-synchronous", "true");
376- sync_notification.set_hint ("x-canonical-non-shaped-icon", "true");
377-
378- /* Show it */
379- try {
380- sync_notification.show ();
381- } catch (GLib.Error e) {
382- warning("Unable to send volume change notification: %s", e.message);
383+ var loud = volume_control.high_volume;
384+ var warn = loud
385+ && this.notify_server_supports_actions
386+ && !this.volume_control.high_volume_approved;
387+
388+ if (warn) {
389+ close_notification(info_notification);
390+ if (_pre_warn_volume == null) {
391+ _pre_warn_volume = new VolumeControl.Volume();
392+ _pre_warn_volume.volume = volume_control.volume.volume;
393+ _pre_warn_volume.reason = volume_control.volume.reason;
394+ }
395+ warn_notification.clear_actions();
396+ warn_notification.add_action ("ok", _("OK"), (n, a) => {
397+ stop_clamp_to_high_timeout();
398+ volume_control.approve_high_volume ();
399+ if (_pre_warn_volume != null) {
400+ var tmp = _pre_warn_volume;
401+ _pre_warn_volume = null;
402+ volume_control.volume = tmp;
403+ }
404+ });
405+ warn_notification.add_action ("cancel", _("Cancel"), (n, a) => {
406+ _pre_warn_volume = null;
407+ });
408+ show_notification(warn_notification);
409+ } else {
410+ close_notification(warn_notification);
411+
412+ if (notify_server_supports_sync && !block_info_notifications) {
413+
414+ /* Determine Label */
415+ unowned string volume_label = loud
416+ ? _("High volume can damage your hearing.")
417+ : "";
418+
419+ /* Choose an icon */
420+ unowned string icon;
421+ if (loud) {
422+ icon = "audio-volume-high";
423+ } else {
424+ var volume = volume_control.volume.volume;
425+
426+ if (volume <= 0.0)
427+ icon = "audio-volume-muted";
428+ else if (volume <= 0.3)
429+ icon = "audio-volume-low";
430+ else if (volume <= 0.7)
431+ icon = "audio-volume-medium";
432+ else
433+ icon = "audio-volume-high";
434+ }
435+
436+ /* Reset the notification */
437+ var n = this.info_notification;
438+ n.update (_("Volume"), volume_label, icon);
439+ n.clear_hints();
440+ n.set_hint ("x-canonical-non-shaped-icon", "true");
441+ n.set_hint ("x-canonical-private-synchronous", "true");
442+ n.set_hint ("x-canonical-value-bar-tint", loud ? "true" : "false");
443+ n.set_hint ("value", (int32)Math.round(get_volume_percent() * 100.0));
444+ show_notification(n);
445+ }
446 }
447 }
448
449@@ -408,49 +433,49 @@
450 return mute_action;
451 }
452
453- SimpleAction volume_action;
454- Action create_volume_action () {
455- /* The action's state is between be in [0.0, 1.0] instead of [0.0,
456- * max_volume], so that we don't need to update the slider menu item
457- * every time allow-amplified-volume is changed. Convert between the
458- * two here, so that we always pass the full range into
459- * volume_control.set_volume().
460- */
461-
462- double volume = this.volume_control.volume.volume / this.max_volume;
463-
464- volume_action = new SimpleAction.stateful ("volume", VariantType.INT32, new Variant.double (volume));
465+ /* return the current volume in the range of [0.0, 1.0] */
466+ private double get_volume_percent() {
467+ return volume_control.volume.volume / this.volume_control.max_volume;
468+ }
469+
470+ /* volume control's range can vary depending on its max_volume property,
471+ * but the action always needs to be in [0.0, 1.0]... */
472+ private Variant create_volume_action_state() {
473+ return new Variant.double (get_volume_percent());
474+ }
475+
476+ private void update_volume_action_state() {
477+ volume_action.set_state(create_volume_action_state());
478+ }
479+
480+ private SimpleAction volume_action;
481+ private Action create_volume_action () {
482+ volume_action = new SimpleAction.stateful ("volume", VariantType.INT32, create_volume_action_state());
483
484 volume_action.change_state.connect ( (action, val) => {
485- double v = val.get_double () * this.max_volume;
486-
487- var vol = new VolumeControl.Volume();
488- vol.volume = v.clamp (0.0, this.max_volume);
489- vol.reason = VolumeControl.VolumeReasons.USER_KEYPRESS;
490- volume_control.volume = vol;
491+ double v = val.get_double () * this.volume_control.max_volume;
492+ volume_control.set_volume_clamp (v, VolumeControl.VolumeReasons.USER_KEYPRESS);
493 });
494
495 /* activating this action changes the volume by the amount given in the parameter */
496- volume_action.activate.connect ( (action, param) => {
497- int delta = param.get_int32 ();
498- double v = volume_control.volume.volume + volume_step_percentage * delta;
499+ volume_action.activate.connect ((a,p) => activate_scroll_action(a,p));
500
501- var vol = new VolumeControl.Volume();
502- vol.volume = v.clamp (0.0, this.max_volume);
503- vol.reason = VolumeControl.VolumeReasons.USER_KEYPRESS;
504- volume_control.volume = vol;
505+ this.volume_control.notify["max-volume"].connect(() => {
506+ update_volume_action_state();
507 });
508
509 this.volume_control.notify["volume"].connect (() => {
510- /* Normalize volume, because the volume action's state is [0.0, 1.0], see create_volume_action() */
511- volume_action.set_state (new Variant.double (this.volume_control.volume.volume / this.max_volume));
512+ update_volume_action_state();
513
514 this.update_root_icon ();
515
516 var reason = volume_control.volume.reason;
517 if (reason == VolumeControl.VolumeReasons.USER_KEYPRESS ||
518 reason == VolumeControl.VolumeReasons.DEVICE_OUTPUT_CHANGE)
519- this.update_sync_notification ();
520+ this.update_notification ();
521+
522+ if ((warn_notification.id != 0) && (_pre_warn_volume != null))
523+ clamp_to_high_soon();
524 });
525
526 this.volume_control.bind_property ("ready", volume_action, "enabled", BindingFlags.SYNC_CREATE);
527@@ -481,7 +506,7 @@
528
529 this.volume_control.notify["high-volume"].connect( () => {
530 high_volume_action.set_state(new Variant.boolean (this.volume_control.high_volume));
531- update_sync_notification();
532+ update_notification();
533 });
534
535 return high_volume_action;
536@@ -604,4 +629,27 @@
537
538 this.update_preferred_players ();
539 }
540+
541+ /** VOLUME CLAMPING **/
542+
543+ private uint _clamp_to_high_timeout = 0;
544+
545+ private void stop_clamp_to_high_timeout() {
546+ if (_clamp_to_high_timeout != 0) {
547+ Source.remove(_clamp_to_high_timeout);
548+ _clamp_to_high_timeout = 0;
549+ }
550+ }
551+
552+ private void clamp_to_high_soon() {
553+ const uint interval_msec = 200;
554+ if (_clamp_to_high_timeout == 0)
555+ _clamp_to_high_timeout = Timeout.add(interval_msec, clamp_to_high_idle);
556+ }
557+
558+ private bool clamp_to_high_idle() {
559+ _clamp_to_high_timeout = 0;
560+ volume_control.clamp_to_high_volume();
561+ return false; // Source.REMOVE;
562+ }
563 }
564
565=== modified file 'src/volume-control-pulse.vala'
566--- src/volume-control-pulse.vala 2015-04-17 17:10:28 +0000
567+++ src/volume-control-pulse.vala 2015-10-13 13:18:26 +0000
568@@ -28,8 +28,8 @@
569 [DBus (name="com.canonical.UnityGreeter.List")]
570 interface GreeterListInterface : Object
571 {
572- public abstract async string get_active_entry () throws IOError;
573- public signal void entry_selected (string entry_name);
574+ public abstract async string get_active_entry () throws IOError;
575+ public signal void entry_selected (string entry_name);
576 }
577
578 public class VolumeControlPulse : VolumeControl
579@@ -44,6 +44,8 @@
580 private bool _is_playing = false;
581 private VolumeControl.Volume _volume = new VolumeControl.Volume();
582 private double _mic_volume = 0.0;
583+ private Settings _settings = new Settings ("com.canonical.indicator.sound");
584+ private Settings _shared_settings = new Settings ("com.ubuntu.sound");
585
586 /* Used by the pulseaudio stream restore extension */
587 private DBusConnection _pconn;
588@@ -92,13 +94,6 @@
589 /** true when a microphone is active **/
590 public override bool active_mic { get; private set; default = false; }
591
592- /** true when high volume warnings should be shown */
593- public override bool high_volume {
594- get {
595- return this._volume.volume > 0.75 && _active_port_headphone && stream == "multimedia";
596- }
597- }
598-
599 public VolumeControlPulse ()
600 {
601 _volume.volume = 0.0;
602@@ -110,19 +105,34 @@
603 _mute_cancellable = new Cancellable ();
604 _volume_cancellable = new Cancellable ();
605
606+ init_all_properties();
607+
608 setup_accountsservice.begin ();
609
610 this.reconnect_to_pulse ();
611 }
612
613+ private void init_all_properties()
614+ {
615+ init_max_volume();
616+ init_high_volume();
617+ init_high_volume_approved();
618+ }
619+
620 ~VolumeControlPulse ()
621 {
622+ stop_all_timers();
623+ }
624+
625+ private void stop_all_timers()
626+ {
627 if (_reconnect_timer != 0) {
628 Source.remove (_reconnect_timer);
629 _reconnect_timer = 0;
630 }
631 stop_local_volume_timer();
632 stop_account_service_volume_timer();
633+ stop_high_volume_approved_timer();
634 }
635
636 /* PulseAudio logic*/
637@@ -212,7 +222,7 @@
638 vol.volume = volume_to_double (i.volume.max ());
639 vol.reason = VolumeControl.VolumeReasons.PULSE_CHANGE;
640 this.volume = vol;
641- }
642+ }
643 }
644
645 private void source_info_cb (Context c, SourceInfo? i, int eol)
646@@ -619,7 +629,6 @@
647 var volume_changed = (value.volume != _volume.volume);
648 debug("Setting volume to %f for profile %d because %d", value.volume, _active_sink_input, value.reason);
649
650- var old_high_volume = this.high_volume;
651 _volume = value;
652
653 /* Make sure we're connected to Pulse and pulse didn't give us the change */
654@@ -631,15 +640,153 @@
655 else
656 context.get_server_info (server_info_cb_for_set_volume);
657
658- if (this.high_volume != old_high_volume)
659- this.notify_property("high-volume");
660
661 if (volume.reason != VolumeControl.VolumeReasons.ACCOUNTS_SERVICE_SET
662 && volume_changed) {
663 start_local_volume_timer();
664 }
665- }
666- }
667+
668+ update_high_volume();
669+ }
670+ }
671+
672+ /** MAX VOLUME PROPERTY **/
673+
674+ private void init_max_volume() {
675+ _settings.changed["normal-volume-decibels"].connect(() => update_max_volume());
676+ _settings.changed["amplified-volume-decibels"].connect(() => update_max_volume());
677+ _shared_settings.changed["allow-amplified-volume"].connect(() => update_max_volume());
678+ update_max_volume();
679+ }
680+ private void update_max_volume () {
681+ var new_max_volume = calculate_max_volume();
682+ if (max_volume != new_max_volume) {
683+ debug("changing max_volume from %f to %f", this.max_volume, new_max_volume);
684+ max_volume = calculate_max_volume();
685+ }
686+ }
687+ private double calculate_max_volume () {
688+ unowned string decibel_key = _shared_settings.get_boolean("allow-amplified-volume")
689+ ? "amplified-volume-decibels"
690+ : "normal-volume-decibels";
691+ var volume_dB = _settings.get_double(decibel_key);
692+ var volume_sw = PulseAudio.Volume.sw_from_dB (volume_dB);
693+ return volume_to_double (volume_sw);
694+ }
695+
696+ /** HIGH VOLUME PROPERTY **/
697+
698+ private bool _warning_volume_enabled;
699+ private double _warning_volume_norms; /* 1.0 == PA_VOLUME_NORM */
700+ private bool _high_volume = false;
701+ public override bool high_volume {
702+ get { return this._high_volume; }
703+ private set { this._high_volume = value; }
704+ }
705+ private void init_high_volume() {
706+ _settings.changed["warning-volume-enabled"].connect(() => update_high_volume_cache());
707+ _settings.changed["warning-volume-decibels"].connect(() => update_high_volume_cache());
708+ update_high_volume_cache();
709+ }
710+ private void update_high_volume_cache() {
711+ var volume_dB = _settings.get_double ("warning-volume-decibels");
712+ var volume_sw = PulseAudio.Volume.sw_from_dB (volume_dB);
713+ var volume_norms = volume_to_double (volume_sw);
714+ _warning_volume_norms = volume_norms;
715+ _warning_volume_enabled = _settings.get_boolean("warning-volume-enabled");
716+ debug("updating high volume cache... enabled %d dB %f sw %lu norm %f", (int)_warning_volume_enabled, volume_dB, volume_sw, volume_norms);
717+ update_high_volume();
718+ }
719+ private void update_high_volume() {
720+ var new_high_volume = calculate_high_volume();
721+ if (high_volume != new_high_volume) {
722+ debug("changing high_volume from %d to %d", (int)high_volume, (int)new_high_volume);
723+ high_volume = new_high_volume;
724+ }
725+ }
726+ private bool calculate_high_volume() {
727+ return calculate_high_volume_from_volume(_volume.volume);
728+ }
729+ private bool calculate_high_volume_from_volume(double volume) {
730+ return _active_port_headphone
731+ && _warning_volume_enabled
732+ && volume >= _warning_volume_norms
733+ && (stream == "multimedia");
734+ }
735+
736+ public override void clamp_to_high_volume() {
737+ if (_high_volume && (_volume.volume > _warning_volume_norms)) {
738+ var vol = new VolumeControl.Volume();
739+ vol.volume = _volume.volume.clamp(0, _warning_volume_norms);
740+ vol.reason = _volume.reason;
741+ debug("Clamping from %f down to %f", _volume.volume, vol.volume);
742+ volume = vol;
743+ }
744+ }
745+
746+ /** HIGH VOLUME APPROVED PROPERTY **/
747+
748+ private bool _high_volume_approved = false;
749+ private uint _high_volume_approved_timer = 0;
750+ private int64 _high_volume_approved_at = 0;
751+ private int64 _high_volume_approved_ttl_usec = 0;
752+ public override bool high_volume_approved {
753+ get { return this._high_volume_approved; }
754+ private set { this._high_volume_approved = value; }
755+ }
756+ private void init_high_volume_approved() {
757+ _settings.changed["warning-volume-confirmation-ttl"].connect(() => update_high_volume_approved_cache());
758+ update_high_volume_approved_cache();
759+ }
760+ private void update_high_volume_approved_cache() {
761+ _high_volume_approved_ttl_usec = _settings.get_int("warning-volume-confirmation-ttl");
762+ _high_volume_approved_ttl_usec *= 1000000;
763+
764+ update_high_volume_approved();
765+ update_high_volume_approved_timer();
766+ }
767+ private void update_high_volume_approved_timer() {
768+ stop_high_volume_approved_timer();
769+ if (_high_volume_approved_at != 0) {
770+ int64 expires_at = _high_volume_approved_at + _high_volume_approved_ttl_usec;
771+ int64 now = GLib.get_monotonic_time();
772+ if (expires_at > now) {
773+ var seconds_left = 1 + ((expires_at - now) / 1000000);
774+ _high_volume_approved_timer = Timeout.add_seconds((uint)seconds_left, on_high_volume_approved_timer);
775+ }
776+ }
777+ }
778+ private void stop_high_volume_approved_timer() {
779+ if (_high_volume_approved_timer != 0) {
780+ Source.remove (_high_volume_approved_timer);
781+ _high_volume_approved_timer = 0;
782+ }
783+ }
784+ private bool on_high_volume_approved_timer() {
785+ _high_volume_approved_timer = 0;
786+ update_high_volume_approved();
787+ return false; /* Source.REMOVE */
788+ }
789+ private void update_high_volume_approved() {
790+ var new_high_volume_approved = calculate_high_volume_approved();
791+ if (high_volume_approved != new_high_volume_approved) {
792+ debug("changing high_volume_approved from %d to %d", (int)high_volume_approved, (int)new_high_volume_approved);
793+ high_volume_approved = new_high_volume_approved;
794+ }
795+ }
796+ private bool calculate_high_volume_approved() {
797+ int64 now = GLib.get_monotonic_time();
798+ return (_high_volume_approved_at != 0)
799+ && (_high_volume_approved_at + _high_volume_approved_ttl_usec >= now);
800+ }
801+ public override void approve_high_volume() {
802+ _high_volume_approved_at = GLib.get_monotonic_time();
803+ update_high_volume_approved();
804+ update_high_volume_approved_timer();
805+ }
806+
807+
808+ /** MIC VOLUME PROPERTY */
809
810 public override double mic_volume {
811 get {
812
813=== modified file 'src/volume-control.vala'
814--- src/volume-control.vala 2015-02-17 16:54:33 +0000
815+++ src/volume-control.vala 2015-10-13 13:18:26 +0000
816@@ -36,12 +36,24 @@
817 public virtual string stream { get { return ""; } }
818 public virtual bool ready { get { return false; } set { } }
819 public virtual bool active_mic { get { return false; } set { } }
820- public virtual bool high_volume { get { return false; } }
821+ public virtual bool high_volume { get { return false; } protected set { } }
822 public virtual bool mute { get { return false; } }
823 public virtual bool is_playing { get { return false; } }
824 private Volume _volume;
825 public virtual Volume volume { get { return _volume; } set { } }
826 public virtual double mic_volume { get { return 0.0; } set { } }
827+ public virtual double max_volume { get { return 1.0; } protected set { } }
828+
829+ public virtual bool high_volume_approved { get { return false; } protected set { } }
830+ public virtual void approve_high_volume() { }
831+ public virtual void clamp_to_high_volume() { }
832
833 public abstract void set_mute (bool mute);
834+
835+ public void set_volume_clamp (double unclamped, VolumeControl.VolumeReasons reason) {
836+ var v = new VolumeControl.Volume();
837+ v.volume = unclamped.clamp (0.0, this.max_volume);
838+ v.reason = reason;
839+ this.volume = v;
840+ }
841 }
842
843=== modified file 'tests/CMakeLists.txt'
844--- tests/CMakeLists.txt 2015-02-09 22:10:22 +0000
845+++ tests/CMakeLists.txt 2015-10-13 13:18:26 +0000
846@@ -163,7 +163,7 @@
847 ###########################
848
849 include_directories(${CMAKE_SOURCE_DIR}/src)
850-add_executable (volume-control-test volume-control-test.cc)
851+add_executable (volume-control-test volume-control-test.cc gschemas.compiled)
852 target_link_libraries (
853 volume-control-test
854 indicator-sound-service-lib
855
856=== modified file 'tests/media-player-user.cc'
857--- tests/media-player-user.cc 2015-01-30 16:05:10 +0000
858+++ tests/media-player-user.cc 2015-10-13 13:18:26 +0000
859@@ -17,6 +17,9 @@
860 * Ted Gould <ted@canonical.com>
861 */
862
863+#include <chrono>
864+#include <future>
865+
866 #include <gtest/gtest.h>
867 #include <gio/gio.h>
868 #include <libdbustest/dbus-test.h>
869@@ -31,24 +34,55 @@
870 {
871
872 protected:
873- DbusTestService * service = NULL;
874+ DbusTestService * testsystem = NULL;
875 AccountsServiceMock service_mock;
876
877+ DbusTestService * testsession = NULL;
878+
879+ DbusTestProcess * systemmonitor = nullptr;
880+ DbusTestProcess * sessionmonitor = nullptr;
881+
882 GDBusConnection * system = NULL;
883+ GDBusConnection * session = NULL;
884 GDBusProxy * proxy = NULL;
885
886+ std::chrono::milliseconds _eventuallyTime = std::chrono::seconds{5};
887+
888 virtual void SetUp() {
889- service = dbus_test_service_new(NULL);
890- dbus_test_service_set_bus(service, DBUS_TEST_SERVICE_BUS_SYSTEM);
891-
892- dbus_test_service_add_task(service, (DbusTestTask*)service_mock);
893- dbus_test_service_start_tasks(service);
894+ /* System Bus */
895+ testsystem = dbus_test_service_new(NULL);
896+ dbus_test_service_set_bus(testsystem, DBUS_TEST_SERVICE_BUS_SYSTEM);
897+
898+ systemmonitor = dbus_test_process_new("dbus-monitor");
899+ dbus_test_process_append_param(systemmonitor, "--system");
900+ dbus_test_task_set_name(DBUS_TEST_TASK(systemmonitor), "System");
901+ dbus_test_service_add_task(testsystem, DBUS_TEST_TASK(systemmonitor));
902+
903+ dbus_test_service_add_task(testsystem, (DbusTestTask*)service_mock);
904+ dbus_test_service_start_tasks(testsystem);
905
906 system = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
907 ASSERT_NE(nullptr, system);
908 g_dbus_connection_set_exit_on_close(system, FALSE);
909 g_object_add_weak_pointer(G_OBJECT(system), (gpointer *)&system);
910
911+ /* Session Bus */
912+ testsession = dbus_test_service_new(NULL);
913+ dbus_test_service_set_bus(testsession, DBUS_TEST_SERVICE_BUS_SESSION);
914+
915+ sessionmonitor = dbus_test_process_new("dbus-monitor");
916+ dbus_test_process_append_param(sessionmonitor, "--session");
917+ dbus_test_task_set_name(DBUS_TEST_TASK(sessionmonitor), "Session");
918+ dbus_test_service_add_task(testsession, DBUS_TEST_TASK(sessionmonitor));
919+
920+ dbus_test_service_start_tasks(testsession);
921+
922+ session = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
923+ ASSERT_NE(nullptr, session);
924+ g_dbus_connection_set_exit_on_close(session, FALSE);
925+ g_object_add_weak_pointer(G_OBJECT(session), (gpointer *)&session);
926+
927+ /* Setup proxy */
928 proxy = g_dbus_proxy_new_sync(system,
929 G_DBUS_PROXY_FLAGS_NONE,
930 NULL,
931@@ -60,10 +94,15 @@
932 }
933
934 virtual void TearDown() {
935+ g_clear_object(&sessionmonitor);
936+ g_clear_object(&systemmonitor);
937+
938 g_clear_object(&proxy);
939- g_clear_object(&service);
940+ g_clear_object(&testsystem);
941+ g_clear_object(&testsession);
942
943 g_object_unref(system);
944+ g_object_unref(session);
945
946 #if 0
947 /* Accounts Service keeps a bunch of references around so we
948@@ -95,8 +134,78 @@
949 void set_property (const gchar * name, GVariant * value) {
950 dbus_test_dbus_mock_object_update_property((DbusTestDbusMock *)service_mock, service_mock.get_sound(), name, value, NULL);
951 }
952+
953+ testing::AssertionResult expectEventually (std::function<testing::AssertionResult(void)> &testfunc) {
954+ auto loop = std::shared_ptr<GMainLoop>(g_main_loop_new(nullptr, FALSE), [](GMainLoop * loop) { if (loop != nullptr) g_main_loop_unref(loop); });
955+
956+ std::promise<testing::AssertionResult> retpromise;
957+ auto retfuture = retpromise.get_future();
958+ auto start = std::chrono::steady_clock::now();
959+
960+ /* The core of the idle function as an object so we can use the C++-isms
961+ of attaching the variables and make this code reasonably readable */
962+ std::function<void(void)> idlefunc = [&loop, &retpromise, &testfunc, &start, this]() -> void {
963+ auto result = testfunc();
964+
965+ if (result == false && _eventuallyTime > (std::chrono::steady_clock::now() - start)) {
966+ return;
967+ }
968+
969+ retpromise.set_value(result);
970+ g_main_loop_quit(loop.get());
971+ };
972+
973+ auto idlesrc = g_idle_add([](gpointer data) -> gboolean {
974+ auto func = reinterpret_cast<std::function<void(void)> *>(data);
975+ (*func)();
976+ return G_SOURCE_CONTINUE;
977+ }, &idlefunc);
978+
979+ g_main_loop_run(loop.get());
980+ g_source_remove(idlesrc);
981+
982+ return retfuture.get();
983+ }
984+
985+ /* Eventually Helpers */
986+ #define _EVENTUALLY_HELPER(oper) \
987+ template <typename... Args> testing::AssertionResult expectEventually##oper (Args&& ... args) { \
988+ std::function<testing::AssertionResult(void)> func = [&]() { \
989+ return testing::internal::CmpHelper##oper(std::forward<Args>(args)...); \
990+ }; \
991+ return expectEventually(func); \
992+ }
993+
994+ _EVENTUALLY_HELPER(EQ);
995+ _EVENTUALLY_HELPER(NE);
996+ _EVENTUALLY_HELPER(LT);
997+ _EVENTUALLY_HELPER(GT);
998+ _EVENTUALLY_HELPER(STREQ);
999+ _EVENTUALLY_HELPER(STRNE);
1000+
1001+ #undef _EVENTUALLY_HELPER
1002 };
1003
1004+/* Helpers */
1005+#define EXPECT_EVENTUALLY_EQ(expected, actual) \
1006+ EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyEQ, expected, actual)
1007+
1008+#define EXPECT_EVENTUALLY_NE(expected, actual) \
1009+ EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyNE, expected, actual)
1010+
1011+#define EXPECT_EVENTUALLY_LT(expected, actual) \
1012+ EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyLT, expected, actual)
1013+
1014+#define EXPECT_EVENTUALLY_GT(expected, actual) \
1015+ EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyGT, expected, actual)
1016+
1017+#define EXPECT_EVENTUALLY_STREQ(expected, actual) \
1018+ EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallySTREQ, expected, actual)
1019+
1020+#define EXPECT_EVENTUALLY_STRNE(expected, actual) \
1021+ EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallySTRNE, expected, actual)
1022+
1023+
1024 TEST_F(MediaPlayerUserTest, BasicObject) {
1025 MediaPlayerUser * player = media_player_user_new("user");
1026 ASSERT_NE(nullptr, player);
1027@@ -125,7 +234,12 @@
1028 g_clear_object(&player);
1029 }
1030
1031-TEST_F(MediaPlayerUserTest, DataSet) {
1032+void
1033+running_update (GObject * obj, GParamSpec * pspec, bool * running) {
1034+ *running = media_player_get_is_running(MEDIA_PLAYER(obj)) == TRUE;
1035+};
1036+
1037+TEST_F(MediaPlayerUserTest, DISABLED_DataSet) {
1038 /* Put data into Acts */
1039 set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time()));
1040 set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince"));
1041@@ -141,11 +255,11 @@
1042 MediaPlayerUser * player = media_player_user_new("user");
1043 ASSERT_NE(nullptr, player);
1044
1045- /* Get the proxy -- and it's precious precious data -- oh, my, precious! */
1046- loop(100);
1047-
1048 /* Ensure even with the proxy we don't have anything */
1049- EXPECT_TRUE(media_player_get_is_running(MEDIA_PLAYER(player)));
1050+ bool running = false;
1051+ g_signal_connect(G_OBJECT(player), "notify::is-running", G_CALLBACK(running_update), &running);
1052+ running_update(G_OBJECT(player), nullptr, &running);
1053+ EXPECT_EVENTUALLY_EQ(true, running);
1054 EXPECT_TRUE(media_player_get_can_raise(MEDIA_PLAYER(player)));
1055 EXPECT_STREQ("user", media_player_get_id(MEDIA_PLAYER(player)));
1056 EXPECT_STREQ("The Player Formerly Known as Prince", media_player_get_name(MEDIA_PLAYER(player)));
1057@@ -168,7 +282,7 @@
1058 g_clear_object(&player);
1059 }
1060
1061-TEST_F(MediaPlayerUserTest, TimeoutTest) {
1062+TEST_F(MediaPlayerUserTest, DISABLED_TimeoutTest) {
1063 /* Put data into Acts -- but 15 minutes ago */
1064 set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time() - 15 * 60 * 1000 * 1000));
1065 set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince"));
1066@@ -180,24 +294,26 @@
1067 set_property("Album", g_variant_new_string("Vinyl is dead"));
1068 set_property("ArtUrl", g_variant_new_string("http://art.url"));
1069
1070- /* Ensure the properties get set before we pull them */
1071- loop(100);
1072-
1073 /* Build our media player */
1074 MediaPlayerUser * player = media_player_user_new("user");
1075 ASSERT_NE(nullptr, player);
1076
1077- /* Get the proxy -- and the old data, so old, like forever */
1078- loop(100);
1079+ bool running = false;
1080+ g_signal_connect(G_OBJECT(player), "notify::is-running", G_CALLBACK(running_update), &running);
1081+ running_update(G_OBJECT(player), nullptr, &running);
1082
1083 /* Ensure that we show up as not running */
1084- EXPECT_FALSE(media_player_get_is_running(MEDIA_PLAYER(player)));
1085+ EXPECT_EVENTUALLY_EQ(false, running);
1086
1087 /* Update to make running */
1088 set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time()));
1089- loop(100);
1090-
1091- EXPECT_TRUE(media_player_get_is_running(MEDIA_PLAYER(player)));
1092+
1093+ EXPECT_EVENTUALLY_EQ(true, running);
1094+
1095+ /* Clear to not run */
1096+ set_property("Timestamp", g_variant_new_uint64(1));
1097+
1098+ EXPECT_EVENTUALLY_EQ(false, running);
1099
1100 g_clear_object(&in_icon);
1101 g_clear_object(&player);
1102
1103=== modified file 'tests/notifications-test.cc'
1104--- tests/notifications-test.cc 2015-02-24 19:05:10 +0000
1105+++ tests/notifications-test.cc 2015-10-13 13:18:26 +0000
1106@@ -350,29 +350,29 @@
1107
1108 /* Set high volume with volume change */
1109 notifications->clearNotifications();
1110- volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE);
1111+ volume_control_mock_set_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), true);
1112 setMockVolume(volumeControl, 0.90);
1113 loop(50);
1114 notev = notifications->getNotifications();
1115 ASSERT_LT(0, notev.size()); /* This passes with one or two since it would just be an update to the first if a second was sent */
1116 EXPECT_EQ("Volume", notev[0].summary);
1117- EXPECT_EQ("High volume", notev[0].body);
1118+ EXPECT_EQ("High volume can damage your hearing.", notev[0].body);
1119 EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]);
1120
1121 /* Move it back */
1122- volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), FALSE);
1123+ volume_control_mock_set_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), false);
1124 setMockVolume(volumeControl, 0.50);
1125 loop(50);
1126
1127 /* Set high volume without level change */
1128 /* NOTE: This can happen if headphones are plugged in */
1129 notifications->clearNotifications();
1130- volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE);
1131+ volume_control_mock_set_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE);
1132 loop(50);
1133 notev = notifications->getNotifications();
1134 ASSERT_EQ(1, notev.size());
1135 EXPECT_EQ("Volume", notev[0].summary);
1136- EXPECT_EQ("High volume", notev[0].body);
1137+ EXPECT_EQ("High volume can damage your hearing.", notev[0].body);
1138 EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]);
1139 }
1140
1141@@ -406,7 +406,7 @@
1142 EXPECT_EQ(1, notev.size());
1143 }
1144
1145-TEST_F(NotificationsTest, ExtendendVolumeNotification) {
1146+TEST_F(NotificationsTest, DISABLED_ExtendendVolumeNotification) {
1147 auto volumeControl = volumeControlMock();
1148 auto soundService = standardService(volumeControl, playerListMock());
1149
1150@@ -424,7 +424,7 @@
1151
1152 /* Allow an amplified volume */
1153 notifications->clearNotifications();
1154- indicator_sound_service_set_allow_amplified_volume(soundService.get(), TRUE);
1155+ //indicator_sound_service_set_allow_amplified_volume(soundService.get(), TRUE);
1156 loop(50);
1157 notev = notifications->getNotifications();
1158 ASSERT_EQ(1, notev.size());
1159@@ -440,7 +440,7 @@
1160
1161 /* Put back */
1162 notifications->clearNotifications();
1163- indicator_sound_service_set_allow_amplified_volume(soundService.get(), FALSE);
1164+ //indicator_sound_service_set_allow_amplified_volume(soundService.get(), FALSE);
1165 loop(50);
1166 notev = notifications->getNotifications();
1167 ASSERT_EQ(1, notev.size());
1168
1169=== modified file 'tests/volume-control-mock.vala'
1170--- tests/volume-control-mock.vala 2015-02-17 16:54:53 +0000
1171+++ tests/volume-control-mock.vala 2015-10-13 13:18:26 +0000
1172@@ -20,12 +20,14 @@
1173
1174 public class VolumeControlMock : VolumeControl
1175 {
1176+ private bool _high_volume = false;
1177+ public override bool high_volume { get { return _high_volume; } protected set { _high_volume = value; } }
1178+ public void set_high_volume(bool b) { high_volume = b; }
1179+
1180 public string mock_stream { get; set; default = "multimedia"; }
1181 public override string stream { get { return mock_stream; } }
1182 public override bool ready { get; set; }
1183 public override bool active_mic { get; set; }
1184- public bool mock_high_volume { get; set; }
1185- public override bool high_volume { get { return mock_high_volume; } }
1186 public bool mock_mute { get; set; }
1187 public override bool mute { get { return mock_mute; } }
1188 public bool mock_is_playing { get; set; }
1189
1190=== modified file 'tests/volume-control-test.cc'
1191--- tests/volume-control-test.cc 2015-02-09 20:14:15 +0000
1192+++ tests/volume-control-test.cc 2015-10-13 13:18:26 +0000
1193@@ -32,7 +32,11 @@
1194 DbusTestService * service = NULL;
1195 GDBusConnection * session = NULL;
1196
1197- virtual void SetUp() {
1198+ virtual void SetUp() override {
1199+
1200+ g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
1201+ g_setenv("GSETTINGS_BACKEND", "memory", TRUE);
1202+
1203 service = dbus_test_service_new(NULL);
1204 dbus_test_service_start_tasks(service);
1205

Subscribers

People subscribed via source and target branches