diff options
author | Xavi Garcia Mena <xavi.garcia.mena@canonical.com> | 2016-02-10 13:22:06 +0000 |
---|---|---|
committer | CI Train Bot <ci-train-bot@canonical.com> | 2016-02-10 13:22:06 +0000 |
commit | cd1eb8bd1cb657a787d3d6fb8b2db26669581c72 (patch) | |
tree | 8ab41e0d437047d35464a3c464c33cf037c35438 | |
parent | 3df5a15f0c7924214c1ae5fbaa5eca32b5c2cd54 (diff) | |
parent | f1bdb863aea00a03acf9501432e2baa70dd9ee8b (diff) | |
download | ayatana-indicator-sound-cd1eb8bd1cb657a787d3d6fb8b2db26669581c72.tar.gz ayatana-indicator-sound-cd1eb8bd1cb657a787d3d6fb8b2db26669581c72.tar.bz2 ayatana-indicator-sound-cd1eb8bd1cb657a787d3d6fb8b2db26669581c72.zip |
This branch modifies the sound indicator on the desktop to only show the playback controls for those players that are active or (if any is running) the last one being active. Fixes: #1213907
Approved by: Charles Kerr, PS Jenkins bot
-rw-r--r-- | data/com.canonical.indicator.sound.gschema.xml | 11 | ||||
-rw-r--r-- | src/service.vala | 15 | ||||
-rw-r--r-- | src/sound-menu.vala | 107 | ||||
-rw-r--r-- | tests/integration/indicator-sound-test-base.cpp | 43 | ||||
-rw-r--r-- | tests/integration/indicator-sound-test-base.h | 9 | ||||
-rw-r--r-- | tests/integration/test-indicator.cpp | 569 | ||||
-rw-r--r-- | tests/service-mocks/media-player-mpris-mock/applications/testplayer2.desktop | 21 | ||||
-rw-r--r-- | tests/service-mocks/media-player-mpris-mock/applications/testplayer3.desktop | 21 | ||||
-rw-r--r-- | tests/sound-menu.cc | 25 |
9 files changed, 776 insertions, 45 deletions
diff --git a/data/com.canonical.indicator.sound.gschema.xml b/data/com.canonical.indicator.sound.gschema.xml index b2ee856..8408883 100644 --- a/data/com.canonical.indicator.sound.gschema.xml +++ b/data/com.canonical.indicator.sound.gschema.xml @@ -102,5 +102,16 @@ </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 29b8670..cb30820 100644 --- a/src/service.vala +++ b/src/service.vala @@ -91,11 +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"); 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)); - 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)); - this.menus.insert ("phone", new SoundMenu ("indicator.phone-settings", SoundMenu.DisplayFlags.SHOW_SILENT_MODE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS)); + 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.@foreach ( (profile, menu) => { this.volume_control.bind_property ("active-mic", menu, "show-mic-volume", BindingFlags.SYNC_CREATE); @@ -109,6 +110,12 @@ public class IndicatorSound.Service: Object { this.volume_control.active_output_changed.connect (menu.update_volume_slider); }); + this.menus.@foreach ( (profile, menu) => { + menu.last_player_updated.connect ((player_id) => { + this.settings.set_value ("last-running-player", player_id); + }); + }); + this.sync_preferred_players (); this.settings.changed["interested-media-players"].connect ( () => { this.sync_preferred_players (); diff --git a/src/sound-menu.vala b/src/sound-menu.vala index 604e484..630dca0 100644 --- a/src/sound-menu.vala +++ b/src/sound-menu.vala @@ -25,10 +25,20 @@ public class SoundMenu: Object HIDE_INACTIVE_PLAYERS = 2, HIDE_PLAYERS = 4, GREETER_PLAYERS = 8, - SHOW_SILENT_MODE = 16 + SHOW_SILENT_MODE = 16, + HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS = 32, + ADD_PLAY_CONTROL_INACTIVE_PLAYER = 64 } - public SoundMenu (string? settings_action, DisplayFlags flags) { + public enum PlayerSectionPosition { + LABEL = 0, + PLAYER_CONTROLS = 1, + PLAYLIST = 2 + } + + const string PLAYBACK_ITEM_TYPE = "com.canonical.unity.playback-item"; + + public SoundMenu (string? settings_action, DisplayFlags flags, string default_player_id) { /* 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. @@ -68,10 +78,14 @@ public class SoundMenu: Object this.hide_players = (flags & DisplayFlags.HIDE_PLAYERS) != 0; this.hide_inactive = (flags & DisplayFlags.HIDE_INACTIVE_PLAYERS) != 0; + this.hide_inactive_player_controls = (flags & DisplayFlags.HIDE_INACTIVE_PLAYERS_PLAY_CONTROLS) != 0; + this.add_play_button_inactive_player = (flags & DisplayFlags.ADD_PLAY_CONTROL_INACTIVE_PLAYER) != 0; 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 () { @@ -148,6 +162,15 @@ public class SoundMenu: Object return -1; } + public void update_all_players_play_section() { + foreach (var player_stored in notify_handlers.get_keys ()) { + int index = this.find_player_section(player_stored); + if (index != -1) { + // just update to verify if we must hide the player controls + update_player_section (player_stored, index); + } + } + } public void add_player (MediaPlayer player) { if (this.notify_handlers.contains (player)) @@ -158,21 +181,23 @@ public class SoundMenu: Object this.update_playlists (player); var handler_id = player.notify["is-running"].connect ( () => { + int index = this.find_player_section(player); if (player.is_running) { - int index = this.find_player_section(player); if (index == -1) { this.insert_player_section (player); } - else { - update_player_section (player, index); - } + number_of_running_players++; } else { + number_of_running_players--; if (this.hide_inactive) this.remove_player_section (player); } - this.update_playlists (player); + + // we need to update the rest of players, because we might have + // a non running player still showing the playback controls + update_all_players_play_section(); }); this.notify_handlers.insert (player, handler_id); @@ -239,8 +264,12 @@ public class SoundMenu: Object bool high_volume_warning_shown = false; bool hide_inactive; bool hide_players = false; + bool hide_inactive_player_controls = false; + bool add_play_button_inactive_player = false; HashTable<MediaPlayer, ulong> notify_handlers; bool greeter_players = false; + int number_of_running_players = 0; + string default_player = ""; /* returns the position in this.menu of the section that's associated with @player */ int find_player_section (MediaPlayer player) { @@ -261,9 +290,21 @@ public class SoundMenu: Object return -1; } + int find_player_playback_controls_section (Menu player_menu) { + int n = player_menu.get_n_items (); + for (int i = 0; i < n; i++) { + string type; + player_menu.get_item_attribute (i, "x-canonical-type", "s", out type); + if (type == PLAYBACK_ITEM_TYPE) + return i; + } + + return -1; + } + MenuItem create_playback_menu_item (MediaPlayer player) { var playback_item = new MenuItem (null, null); - playback_item.set_attribute ("x-canonical-type", "s", "com.canonical.unity.playback-item"); + playback_item.set_attribute ("x-canonical-type", "s", PLAYBACK_ITEM_TYPE); if (player.is_running) { if (player.can_do_play) { playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id); @@ -274,6 +315,10 @@ public class SoundMenu: Object if (player.can_do_prev) { playback_item.set_attribute ("x-canonical-previous-action", "s", "indicator.previous." + player.id); } + } else { + if (this.add_play_button_inactive_player) { + playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id); + } } return playback_item; } @@ -301,24 +346,10 @@ public class SoundMenu: Object player_item.set_attribute_value ("icon", icon.serialize ()); section.append_item (player_item); - var playback_item = new MenuItem (null, null); - playback_item.set_attribute ("x-canonical-type", "s", "com.canonical.unity.playback-item"); - playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id + ".disabled"); - playback_item.set_attribute ("x-canonical-next-action", "s", "indicator.next." + player.id + ".disabled"); - playback_item.set_attribute ("x-canonical-previous-action", "s", "indicator.previous." + player.id + ".disabled"); - - if (player.is_running) { - if (player.can_do_play) { - playback_item.set_attribute ("x-canonical-play-action", "s", "indicator.play." + player.id); - } - if (player.can_do_next) { - playback_item.set_attribute ("x-canonical-next-action", "s", "indicator.next." + player.id); - } - if (player.can_do_prev) { - playback_item.set_attribute ("x-canonical-previous-action", "s", "indicator.previous." + player.id); - } + if (player.is_running|| !this.hide_inactive_player_controls || player.id == this.default_player) { + var playback_item = create_playback_menu_item (player); + section.insert_item (PlayerSectionPosition.PLAYER_CONTROLS, playback_item); } - section.append_item (playback_item); /* Add new players to the end of the player sections, just before the settings */ if (settings_shown) { @@ -339,13 +370,25 @@ public class SoundMenu: Object void update_player_section (MediaPlayer player, int index) { var player_section = this.menu.get_item_link(index, Menu.LINK_SECTION) as Menu; - if (player_section.get_n_items () == 2 || player_section.get_n_items () == 3) { - // we have 2 items, the second one is the playback item - // if we have 3 items, it means we also have the playlist item. - // remove the playbak item first - player_section.remove (1); + + 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) { MenuItem playback_item = create_playback_menu_item (player); - player_section.insert_item (1, playback_item); + if (play_control_index != -1) { + player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS); + } + player_section.insert_item (PlayerSectionPosition.PLAYER_CONTROLS, playback_item); + } else { + if (play_control_index != -1 && number_of_running_players >= 1) { + // remove both, playlist and play controls + player_section.remove (PlayerSectionPosition.PLAYLIST); + player_section.remove (PlayerSectionPosition.PLAYER_CONTROLS); + } } } @@ -404,4 +447,6 @@ public class SoundMenu: Object return slider; } + + public signal void last_player_updated (string player_id); } diff --git a/tests/integration/indicator-sound-test-base.cpp b/tests/integration/indicator-sound-test-base.cpp index 91abf42..f61857e 100644 --- a/tests/integration/indicator-sound-test-base.cpp +++ b/tests/integration/indicator-sound-test-base.cpp @@ -192,16 +192,53 @@ bool IndicatorSoundTestBase::runProcess(QProcess& proc) bool IndicatorSoundTestBase::startTestMprisPlayer(QString const& playerName) { - testPlayer1.terminate(); - testPlayer1.start(MEDIA_PLAYER_MPRIS_BIN, QStringList() + if (!stopTestMprisPlayer(playerName)) + { + return false; + } + TestPlayer player; + player.name = playerName; + player.process.reset(new QProcess()); + player.process->start(MEDIA_PLAYER_MPRIS_BIN, QStringList() << playerName); - if (!testPlayer1.waitForStarted()) + if (!player.process->waitForStarted()) + { + qWarning() << "ERROR STARTING PLAYER " << playerName; return false; + } + testPlayers.push_back(player); return true; } +bool IndicatorSoundTestBase::stopTestMprisPlayer(QString const& playerName) +{ + bool terminateOK = true; + int index = findRunningTestMprisPlayer(playerName); + if (index != -1) + { + testPlayers[index].process->terminate(); + if (!testPlayers[index].process->waitForFinished()) + terminateOK = false; + testPlayers.remove(index); + } + + return terminateOK; +} + +int IndicatorSoundTestBase::findRunningTestMprisPlayer(QString const& playerName) +{ + for (int i = 0; i < testPlayers.size(); i++) + { + if (testPlayers.at(i).name == playerName) + { + return i; + } + } + return -1; +} + bool IndicatorSoundTestBase::setTestMprisPlayerProperty(QString const &testPlayer, QString const &property, bool value) { QProcess setProperty; diff --git a/tests/integration/indicator-sound-test-base.h b/tests/integration/indicator-sound-test-base.h index d9d3289..969fd69 100644 --- a/tests/integration/indicator-sound-test-base.h +++ b/tests/integration/indicator-sound-test-base.h @@ -81,6 +81,8 @@ protected: bool runProcess(QProcess&); bool startTestMprisPlayer(QString const& playerName); + bool stopTestMprisPlayer(QString const& playerName); + int findRunningTestMprisPlayer(QString const& playerName); bool setTestMprisPlayerProperty(QString const &testPlayer, QString const &property, bool value); @@ -156,6 +158,13 @@ protected: QProcess testPlayer1; + struct TestPlayer + { + std::shared_ptr<QProcess> process; + QString name; + }; + QVector<TestPlayer> testPlayers; + std::unique_ptr<MenusInterface> menu_interface_; std::unique_ptr<DBusPropertiesInterface> accounts_interface_; diff --git a/tests/integration/test-indicator.cpp b/tests/integration/test-indicator.cpp index 9224b73..33a27af 100644 --- a/tests/integration/test-indicator.cpp +++ b/tests/integration/test-indicator.cpp @@ -367,6 +367,574 @@ TEST_F(TestIndicator, DesktopAddMprisPlayer) .label("Sound Settings…") ) ).match()); + + // stop the test player + EXPECT_TRUE(stopTestMprisPlayer("testplayer1")); + + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); +} + +TEST_F(TestIndicator, DesktopMprisPlayersPlaybackControls) +{ + double INITIAL_VOLUME = 0.0; + + ASSERT_NO_THROW(startAccountsService()); + EXPECT_TRUE(clearGSettingsPlayers()); + ASSERT_NO_THROW(startPulseDesktop()); + + // initialize volumes in pulseaudio + EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); + EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); + + // start the test player + EXPECT_TRUE(startTestMprisPlayer("testplayer1")); + + // start now the indicator, so it picks the new volumes + ASSERT_NO_THROW(startIndicator()); + + // check that the player is added + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + // start the second test player + EXPECT_TRUE(startTestMprisPlayer("testplayer2")); + + // check that the player is added + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer2.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer2.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + // start the third test player + EXPECT_TRUE(startTestMprisPlayer("testplayer3")); + + // check that the player is added + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer2.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer2.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer3.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer3.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer3.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + // stop the test player + EXPECT_TRUE(stopTestMprisPlayer("testplayer3")); + + // check that player 3 is present, but it has no playback controls + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer2.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer2.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + EXPECT_TRUE(stopTestMprisPlayer("testplayer2")); + + // check that player 2 is present, but it has no playback controls + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + EXPECT_TRUE(stopTestMprisPlayer("testplayer1")); + + // check that player 1 is present, and it still has the playback controls + // as it was the last one being executed + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + // start the third test player + EXPECT_TRUE(startTestMprisPlayer("testplayer3")); + + // check that player 3 is the only one with playback controls + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer3.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer3.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer3.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + // start the rest of players + EXPECT_TRUE(startTestMprisPlayer("testplayer1")); + EXPECT_TRUE(startTestMprisPlayer("testplayer2")); + + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer2.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer2.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer3.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer3.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer3.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); + + // stop all players + EXPECT_TRUE(stopTestMprisPlayer("testplayer1")); + EXPECT_TRUE(stopTestMprisPlayer("testplayer2")); + EXPECT_TRUE(stopTestMprisPlayer("testplayer3")); + + // check that player 3 is the only one with playback controls + // as it was the last one being stopped + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) + .item(mh::MenuItemMatcher() + .action("indicator.root") + .string_attribute("x-canonical-type", "com.canonical.indicator.root") + .string_attribute("x-canonical-secondary-action", "indicator.mute") + .mode(mh::MenuItemMatcher::Mode::all) + .submenu() + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher().checkbox() + .label("Mute") + ) + .item(volumeSlider(INITIAL_VOLUME, "Volume")) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer1.desktop") + .label("TestPlayer1") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer2.desktop") + .label("TestPlayer2") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + ) + .item(mh::MenuItemMatcher() + .section() + .item(mh::MenuItemMatcher() + .action("indicator.testplayer3.desktop") + .label("TestPlayer3") + .themed_icon("icon", {"testplayer"}) + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") + ) + .item(mh::MenuItemMatcher() + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer3.desktop") + .string_attribute("x-canonical-play-action","indicator.play.testplayer3.desktop") + .string_attribute("x-canonical-next-action","indicator.next.testplayer3.desktop") + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") + ) + ) + .item(mh::MenuItemMatcher() + .label("Sound Settings…") + ) + ).match()); } TEST_F(TestIndicator, DesktopMprisPlayerButtonsState) @@ -817,7 +1385,6 @@ TEST_F(TestIndicator, DISABLED_PhoneNotificationWarningVolume) // try again... notificationsSpy.clear(); - qWarning() << "-----------------------------------------------------------"; // change volume to 1.0... warning should be emitted setActionValue("volume", QVariant::fromValue(1.0)); EXPECT_TRUE(waitVolumeChangedInIndicator()); diff --git a/tests/service-mocks/media-player-mpris-mock/applications/testplayer2.desktop b/tests/service-mocks/media-player-mpris-mock/applications/testplayer2.desktop new file mode 100644 index 0000000..579a0bf --- /dev/null +++ b/tests/service-mocks/media-player-mpris-mock/applications/testplayer2.desktop @@ -0,0 +1,21 @@ +[Desktop Entry] +Name=TestPlayer2 +GenericName=Test Player 2 +X-GNOME-FullName=Test Player 2 +Comment=Play and organize your music collection +Keywords=Audio;Song;MP3;CD;Podcast;MTP;iPod;Playlist;Last.fm;UPnP;DLNA;Radio; +Exec=echo %U +Terminal=false +Type=Application +Icon=testplayer +X-GNOME-DocPath=testplayer/testplayer.xml +Categories=GNOME;GTK;AudioVideo;Audio;Player; +MimeType=application/x-ogg;application/ogg;audio/x-vorbis+ogg;audio/x-scpls;audio/x-mp3;audio/x-mpeg;audio/mpeg;audio/x-mpegurl;audio/x-flac;audio/mp4;x-scheme-handler/itms;x-scheme-handler/itmss; +StartupNotify=true +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=testplayer +X-GNOME-Bugzilla-Component=general +X-GNOME-Bugzilla-OtherBinaries=rhythmbox-client;rhythmbox-metadata; +X-GNOME-Bugzilla-Version=3.1 +X-GNOME-UsesNotifications=true + diff --git a/tests/service-mocks/media-player-mpris-mock/applications/testplayer3.desktop b/tests/service-mocks/media-player-mpris-mock/applications/testplayer3.desktop new file mode 100644 index 0000000..b3bfc6b --- /dev/null +++ b/tests/service-mocks/media-player-mpris-mock/applications/testplayer3.desktop @@ -0,0 +1,21 @@ +[Desktop Entry] +Name=TestPlayer3 +GenericName=Test Player 3 +X-GNOME-FullName=Test Player 3 +Comment=Play and organize your music collection +Keywords=Audio;Song;MP3;CD;Podcast;MTP;iPod;Playlist;Last.fm;UPnP;DLNA;Radio; +Exec=echo %U +Terminal=false +Type=Application +Icon=testplayer +X-GNOME-DocPath=testplayer/testplayer.xml +Categories=GNOME;GTK;AudioVideo;Audio;Player; +MimeType=application/x-ogg;application/ogg;audio/x-vorbis+ogg;audio/x-scpls;audio/x-mp3;audio/x-mpeg;audio/mpeg;audio/x-mpegurl;audio/x-flac;audio/mp4;x-scheme-handler/itms;x-scheme-handler/itmss; +StartupNotify=true +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=testplayer +X-GNOME-Bugzilla-Component=general +X-GNOME-Bugzilla-OtherBinaries=rhythmbox-client;rhythmbox-metadata; +X-GNOME-Bugzilla-Version=3.1 +X-GNOME-UsesNotifications=true + diff --git a/tests/sound-menu.cc b/tests/sound-menu.cc index 75a661b..2576d19 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,9 +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(canPlay ? "indicator.play.player-id" : "indicator.play.player-id.disabled")); - verify_item_attribute(section, 1, "x-canonical-next-action", g_variant_new_string(canNext ? "indicator.next.player-id" : "indicator.next.player-id.disabled")); - verify_item_attribute(section, 1, "x-canonical-previous-action", g_variant_new_string(canPrev ? "indicator.previous.player-id" : "indicator.previous.player-id.disabled")); + //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) { + 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) { + 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")); + } g_clear_object(§ion); @@ -112,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); @@ -121,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"); |