diff options
-rw-r--r-- | data/com.canonical.indicator.sound.gschema.xml | 15 | ||||
-rw-r--r-- | src/service.vala | 18 | ||||
-rw-r--r-- | src/sound-menu.vala | 33 | ||||
-rw-r--r-- | src/volume-control-pulse.vala | 39 | ||||
-rw-r--r-- | src/volume-control.vala | 2 | ||||
-rw-r--r-- | tests/integration/indicator-sound-test-base.cpp | 33 | ||||
-rw-r--r-- | tests/integration/indicator-sound-test-base.h | 4 | ||||
-rw-r--r-- | tests/sound-menu.cc | 32 |
8 files changed, 127 insertions, 49 deletions
diff --git a/data/com.canonical.indicator.sound.gschema.xml b/data/com.canonical.indicator.sound.gschema.xml index 8408883..06bfe74 100644 --- a/data/com.canonical.indicator.sound.gschema.xml +++ b/data/com.canonical.indicator.sound.gschema.xml @@ -59,10 +59,10 @@ <description> How long to remember a user's approval of the confirmation dialog discussed in the description of 'warning-volume-enabled'. - + The default value (72,000 seconds) corresponds to the 20 hours suggested by EU standard EN 60950-1/Al2: “The acknowledgement does not need to be repeated - more than once every 20 h of cumulative listening time.” + more than once every 20 h of cumulative listening time.” </description> </key> <key name="warning-volume-decibels" type="d"> @@ -102,16 +102,5 @@ </description> </key> - <key name="last-running-player" type="s"> - <default>""</default> - <summary>Stores which was the last running music player.</summary> - <description> - To make the last running player persistent and be able to set its playback controls - we store which was the last player running id. - - The default value ("") corresponds to no player. - </description> - </key> - </schema> </schemalist> diff --git a/src/service.vala b/src/service.vala index cb30820..d55a3c8 100644 --- a/src/service.vala +++ b/src/service.vala @@ -91,12 +91,12 @@ public class IndicatorSound.Service: Object { this.actions.add_action (this.create_high_volume_action ()); this.actions.add_action (this.create_volume_sync_action ()); - string last_player = this.settings.get_string ("last-running-player"); + // OLD string last_player = this.settings.get_string ("last-running-player"); this.menus = new HashTable<string, SoundMenu> (str_hash, str_equal); - this.menus.insert ("desktop_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.HIDE_PLAYERS | SoundMenu.DisplayFlags.GREETER_PLAYERS, last_player)); - this.menus.insert ("phone_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_SILENT_MODE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS | SoundMenu.DisplayFlags.GREETER_PLAYERS, last_player)); - this.menus.insert ("desktop", new SoundMenu ("indicator.desktop-settings", SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS | SoundMenu.DisplayFlags.ADD_PLAY_CONTROL_INACTIVE_PLAYER, last_player)); - this.menus.insert ("phone", new SoundMenu ("indicator.phone-settings", SoundMenu.DisplayFlags.SHOW_SILENT_MODE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS, last_player)); + this.menus.insert ("desktop_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.HIDE_PLAYERS | SoundMenu.DisplayFlags.GREETER_PLAYERS)); + this.menus.insert ("phone_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_SILENT_MODE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS | SoundMenu.DisplayFlags.GREETER_PLAYERS)); + this.menus.insert ("desktop", new SoundMenu ("indicator.desktop-settings", SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS | SoundMenu.DisplayFlags.ADD_PLAY_CONTROL_INACTIVE_PLAYER)); + this.menus.insert ("phone", new SoundMenu ("indicator.phone-settings", SoundMenu.DisplayFlags.SHOW_SILENT_MODE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS)); this.menus.@foreach ( (profile, menu) => { this.volume_control.bind_property ("active-mic", menu, "show-mic-volume", BindingFlags.SYNC_CREATE); @@ -112,7 +112,13 @@ public class IndicatorSound.Service: Object { this.menus.@foreach ( (profile, menu) => { menu.last_player_updated.connect ((player_id) => { - this.settings.set_value ("last-running-player", player_id); + this.volume_control.last_running_player = player_id; + }); + }); + + this.volume_control.notify["last-running-player"].connect(() => { + this.menus.@foreach ( (profile, menu) => { + menu.set_default_player (this.volume_control.last_running_player); }); }); diff --git a/src/sound-menu.vala b/src/sound-menu.vala index 630dca0..5aa94fe 100644 --- a/src/sound-menu.vala +++ b/src/sound-menu.vala @@ -38,7 +38,7 @@ public class SoundMenu: Object const string PLAYBACK_ITEM_TYPE = "com.canonical.unity.playback-item"; - public SoundMenu (string? settings_action, DisplayFlags flags, string default_player_id) { + public SoundMenu (string? settings_action, DisplayFlags flags) { /* A sound menu always has at least two sections: the volume section (this.volume_section) * at the start of the menu, and the settings section at the end. Between those two, * it has a dynamic amount of player sections, one for each registered player. @@ -83,9 +83,6 @@ public class SoundMenu: Object this.notify_handlers = new HashTable<MediaPlayer, ulong> (direct_hash, direct_equal); this.greeter_players = (flags & DisplayFlags.GREETER_PLAYERS) != 0; - - this.default_player = default_player_id; - } ~SoundMenu () { @@ -95,6 +92,16 @@ public class SoundMenu: Object } } + public void set_default_player (string default_player_id) { + this.default_player = default_player_id; + foreach (var player_stored in notify_handlers.get_keys ()) { + int index = this.find_player_section(player_stored); + if (index != -1 && player_stored.id == this.default_player) { + add_player_playback_controls (player_stored, index, true); + } + } + } + DBusConnection? bus = null; uint export_id = 0; @@ -368,16 +375,11 @@ public class SoundMenu: Object this.menu.remove (index); } - void update_player_section (MediaPlayer player, int index) { + void add_player_playback_controls (MediaPlayer player, int index, bool adding_default_player) { var player_section = this.menu.get_item_link(index, Menu.LINK_SECTION) as Menu; int play_control_index = find_player_playback_controls_section (player_section); - if (player.is_running && number_of_running_players == 1) { - // this is the first or the last player running... - // store its id - this.last_player_updated (player.id); - } - if (player.is_running || !this.hide_inactive_player_controls) { + if (player.is_running || !this.hide_inactive_player_controls || (number_of_running_players == 0 && adding_default_player) ) { MenuItem playback_item = create_playback_menu_item (player); if (play_control_index != -1) { player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS); @@ -389,7 +391,16 @@ public class SoundMenu: Object player_section.remove (PlayerSectionPosition.PLAYLIST); player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS); } + } + } + + void update_player_section (MediaPlayer player, int index) { + if (player.is_running && number_of_running_players == 1) { + // this is the first or the last player running... + // store its id + this.last_player_updated (player.id); } + add_player_playback_controls (player, index, false); } void update_playlists (MediaPlayer player) { diff --git a/src/volume-control-pulse.vala b/src/volume-control-pulse.vala index 6021447..cdc6953 100644 --- a/src/volume-control-pulse.vala +++ b/src/volume-control-pulse.vala @@ -59,15 +59,29 @@ public class VolumeControlPulse : VolumeControl private GreeterListInterface _greeter_proxy; private Cancellable _mute_cancellable; private Cancellable _volume_cancellable; + private Cancellable _last_running_player_cancellable; private uint _local_volume_timer = 0; private uint _accountservice_volume_timer = 0; private bool _send_next_local_volume = false; private double _account_service_volume = 0.0; private VolumeControl.ActiveOutput _active_output = VolumeControl.ActiveOutput.SPEAKERS; + private string _last_running_player = ""; /** true when a microphone is active **/ public override bool active_mic { get; private set; default = false; } + public override string last_running_player + { + get + { + return _last_running_player; + } + set + { + sync_last_running_player_to_accountsservice.begin (value); + } + } + public VolumeControlPulse (IndicatorSound.Options options, PulseAudio.GLibMainLoop loop) { base(options); @@ -79,6 +93,7 @@ public class VolumeControlPulse : VolumeControl _mute_cancellable = new Cancellable (); _volume_cancellable = new Cancellable (); + _last_running_player_cancellable = new Cancellable(); setup_accountsservice.begin (); @@ -790,6 +805,13 @@ public class VolumeControlPulse : VolumeControl var mute = mute_variant.get_boolean (); set_mute_internal (mute); } + + Variant last_running_player_variant = changed_properties.lookup_value ("LastRunningPlayer", VariantType.STRING); + if (last_running_player_variant != null) { + var last_player = last_running_player_variant.get_string (); + _last_running_player = last_player; + this.notify_property("last-running-player"); + } } private async void setup_user_proxy (string? username_in = null) @@ -881,6 +903,22 @@ public class VolumeControlPulse : VolumeControl } } + private async void sync_last_running_player_to_accountsservice (string last_running_player) + { + if (_user_proxy == null) + return; + + _last_running_player_cancellable.cancel (); + _last_running_player_cancellable.reset (); + + try { + yield _user_proxy.get_connection ().call (_user_proxy.get_name (), _user_proxy.get_object_path (), "org.freedesktop.DBus.Properties", "Set", new Variant ("(ssv)", _user_proxy.get_interface_name (), "LastRunningPlayer", new Variant ("s", last_running_player)), null, DBusCallFlags.NONE, -1, _last_running_player_cancellable); + } catch (GLib.Error e) { + warning ("unable to sync last running player to AccountsService: %s", e.message); + } + _last_running_player = last_running_player; + } + private async void sync_volume_to_accountsservice (VolumeControl.Volume volume) { if (_user_proxy == null) @@ -889,6 +927,7 @@ public class VolumeControlPulse : VolumeControl _volume_cancellable.cancel (); _volume_cancellable.reset (); + warning("Interface name: %s", _user_proxy.get_interface_name ()); try { yield _user_proxy.get_connection ().call (_user_proxy.get_name (), _user_proxy.get_object_path (), "org.freedesktop.DBus.Properties", "Set", new Variant ("(ssv)", _user_proxy.get_interface_name (), "Volume", new Variant ("d", volume.volume)), null, DBusCallFlags.NONE, -1, _volume_cancellable); } catch (GLib.Error e) { diff --git a/src/volume-control.vala b/src/volume-control.vala index 3d02f70..137e7b6 100644 --- a/src/volume-control.vala +++ b/src/volume-control.vala @@ -84,4 +84,6 @@ public abstract class VolumeControl : Object public abstract VolumeControl.ActiveOutput active_output(); public signal void active_output_changed (VolumeControl.ActiveOutput active_output); + + public virtual string last_running_player { get { return ""; } set { } } } diff --git a/tests/integration/indicator-sound-test-base.cpp b/tests/integration/indicator-sound-test-base.cpp index f61857e..8242fb6 100644 --- a/tests/integration/indicator-sound-test-base.cpp +++ b/tests/integration/indicator-sound-test-base.cpp @@ -448,13 +448,40 @@ bool IndicatorSoundTestBase::initializeMenuChangedSignal() return true; } -bool IndicatorSoundTestBase::waitVolumeChangedInIndicator() +QVariant IndicatorSoundTestBase::waitPropertyChanged(QString property) { + QVariant ret_val; if (signal_spy_volume_changed_) { - return signal_spy_volume_changed_->wait(); + signal_spy_volume_changed_->wait(); + if (signal_spy_volume_changed_->count()) + { + QList<QVariant> arguments = signal_spy_volume_changed_->takeFirst(); + if (arguments.size() == 3 && static_cast<QMetaType::Type>(arguments.at(1).type()) == QMetaType::QVariantMap) + { + QVariantMap map = arguments.at(1).toMap(); + QMapIterator<QString, QVariant> iter(map); + while (iter.hasNext()) { + iter.next(); + if (iter.key() == property) + { + return iter.value(); + } + } + } + } } - return false; + return ret_val; +} +bool IndicatorSoundTestBase::waitVolumeChangedInIndicator() +{ + QVariant val = waitPropertyChanged("Volume"); + return !val.isNull(); +} + +QVariant IndicatorSoundTestBase::waitLastRunningPlayerChanged() +{ + return waitPropertyChanged("LastRunningPlayer"); } void IndicatorSoundTestBase::initializeAccountsInterface() diff --git a/tests/integration/indicator-sound-test-base.h b/tests/integration/indicator-sound-test-base.h index 969fd69..ecdbd7d 100644 --- a/tests/integration/indicator-sound-test-base.h +++ b/tests/integration/indicator-sound-test-base.h @@ -144,6 +144,10 @@ protected: float getVolumeValue(bool *isValid = nullptr); + QVariant waitPropertyChanged(QString property); + + QVariant waitLastRunningPlayerChanged(); + QtDBusTest::DBusTestRunner dbusTestRunner; QtDBusMock::DBusMock dbusMock; diff --git a/tests/sound-menu.cc b/tests/sound-menu.cc index 2576d19..79ae703 100644 --- a/tests/sound-menu.cc +++ b/tests/sound-menu.cc @@ -62,7 +62,7 @@ class SoundMenuTest : public ::testing::Test void check_player_control_buttons(bool canPlay, bool canNext, bool canPrev) { - SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE, ""); + SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE); MediaPlayerTrack * track = media_player_track_new("Artist", "Title", "Album", "http://art.url"); @@ -96,22 +96,22 @@ class SoundMenuTest : public ::testing::Test /* Player control */ verify_item_attribute(section, 1, "x-canonical-type", g_variant_new_string("com.canonical.unity.playback-item")); - //verify_item_attribute(section, 1, "x-canonical-play-action", g_variant_new_string("")); - if (!canPlay) { + //verify_item_attribute(section, 1, "x-canonical-play-action", g_variant_new_string("")); + if (!canPlay) { verify_item_attribute_is_not_set(section, 1, "x-canonical-play-action", G_VARIANT_TYPE_STRING); - } else { - verify_item_attribute(section, 1, "x-canonical-play-action", g_variant_new_string("indicator.play.player-id")); - } - if (!canNext) { + } else { + verify_item_attribute(section, 1, "x-canonical-play-action", g_variant_new_string("indicator.play.player-id")); + } + if (!canNext) { verify_item_attribute_is_not_set(section, 1, "x-canonical-next-action", G_VARIANT_TYPE_STRING); - } else { - verify_item_attribute(section, 1, "x-canonical-next-action", g_variant_new_string("indicator.next.player-id")); - } - if (!canPrev) { + } else { + verify_item_attribute(section, 1, "x-canonical-next-action", g_variant_new_string("indicator.next.player-id")); + } + if (!canPrev) { verify_item_attribute_is_not_set(section, 1, "x-canonical-previous-action", G_VARIANT_TYPE_STRING); - } else { - verify_item_attribute(section, 1, "x-canonical-previous-action", g_variant_new_string("indicator.previous.player-id")); - } + } else { + verify_item_attribute(section, 1, "x-canonical-previous-action", g_variant_new_string("indicator.previous.player-id")); + } g_clear_object(§ion); @@ -125,7 +125,7 @@ class SoundMenuTest : public ::testing::Test }; TEST_F(SoundMenuTest, BasicObject) { - SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE, ""); + SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE); ASSERT_NE(nullptr, menu); @@ -134,7 +134,7 @@ TEST_F(SoundMenuTest, BasicObject) { } TEST_F(SoundMenuTest, AddRemovePlayer) { - SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE, ""); + SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE); MediaPlayerTrack * track = media_player_track_new("Artist", "Title", "Album", "http://art.url"); |