aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/volume-control-pulse.vala11
-rw-r--r--tests/dbus-types/CMakeLists.txt5
-rw-r--r--tests/dbus-types/dbus-types.h4
-rw-r--r--tests/dbus-types/org.freedesktop.Notifications.xml47
-rw-r--r--tests/integration/indicator-sound-test-base.cpp319
-rw-r--r--tests/integration/indicator-sound-test-base.h29
-rw-r--r--tests/integration/test-indicator.cpp288
7 files changed, 647 insertions, 56 deletions
diff --git a/src/volume-control-pulse.vala b/src/volume-control-pulse.vala
index 042c1c1..ab0d6d7 100644
--- a/src/volume-control-pulse.vala
+++ b/src/volume-control-pulse.vala
@@ -206,10 +206,11 @@ public class VolumeControlPulse : VolumeControl
* checking for the port name. On touch (with the pulseaudio droid element)
* the headset/headphone port is called 'output-headset' and 'output-headphone'.
* On the desktop this is usually called 'analog-output-headphones' */
- if (i.active_port != null &&
- (i.active_port.name == "output-wired_headset" ||
- i.active_port.name == "output-wired_headphone" ||
- i.active_port.name == "analog-output-headphones")) {
+ if ( (i.active_port != null &&
+ (i.active_port.name == "output-wired_headset" ||
+ i.active_port.name == "output-wired_headphone" ||
+ i.active_port.name == "analog-output-headphones")) ||
+ (i.name == "indicator_sound_test_headphones")) {
_active_port_headphone = true;
} else {
_active_port_headphone = false;
@@ -711,7 +712,7 @@ public class VolumeControlPulse : VolumeControl
private bool calculate_high_volume_from_volume(double volume) {
return _active_port_headphone
&& _warning_volume_enabled
- && volume >= _warning_volume_norms
+ && volume > _warning_volume_norms
&& (stream == "multimedia");
}
diff --git a/tests/dbus-types/CMakeLists.txt b/tests/dbus-types/CMakeLists.txt
index 30dff60..cb7f512 100644
--- a/tests/dbus-types/CMakeLists.txt
+++ b/tests/dbus-types/CMakeLists.txt
@@ -28,11 +28,16 @@ set(dbusinterface_actions_xml "org.gtk.Actions.xml")
set_source_files_properties(${dbusinterface_actions_xml} PROPERTIES
CLASSNAME MenusInterface)
+set(dbusinterface_notifications_xml "org.freedesktop.Notifications.xml")
+set_source_files_properties(${dbusinterface_notifications_xml} PROPERTIES
+ CLASSNAME NotificationsInterface)
+
qt5_add_dbus_interface(interface_files ${dbusinterface_streamrestore_xml} stream_restore_interface)
qt5_add_dbus_interface(interface_files ${dbusinterface_properties_xml} dbus_properties_interface)
qt5_add_dbus_interface(interface_files ${dbusinterface_accounts_xml} dbus_accounts_interface)
qt5_add_dbus_interface(interface_files ${dbusinterface_accountssound_xml} dbus_accountssound_interface)
qt5_add_dbus_interface(interface_files ${dbusinterface_actions_xml} dbus_menus_interface)
+qt5_add_dbus_interface(interface_files ${dbusinterface_notifications_xml} dbus_notifications_interface)
add_library(
sound-indicator-dbus-interfaces
diff --git a/tests/dbus-types/dbus-types.h b/tests/dbus-types/dbus-types.h
index 4abe9ff..b75acf0 100644
--- a/tests/dbus-types/dbus-types.h
+++ b/tests/dbus-types/dbus-types.h
@@ -40,5 +40,9 @@ namespace DBusTypes
static constexpr char const* STREAM_RESTORE_ENTRY_NAME = "org.PulseAudio.Ext.StreamRestore1.RestoreEntry";
+ static constexpr char const* MAIN_SERVICE_PATH = "/com/canonical/indicator/sound";
+
+ static constexpr char const* ACTIONS_INTERFACE = "org.gtk.Actions";
+
} // namespace DBusTypes
diff --git a/tests/dbus-types/org.freedesktop.Notifications.xml b/tests/dbus-types/org.freedesktop.Notifications.xml
new file mode 100644
index 0000000..f7d923e
--- /dev/null
+++ b/tests/dbus-types/org.freedesktop.Notifications.xml
@@ -0,0 +1,47 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.Notifications">
+ <signal name="NotificationClosed">
+ <arg name="id" type="u" direction="out"/>
+ <arg name="reason" type="u" direction="out"/>
+ </signal>
+ <signal name="ActionInvoked">
+ <arg name="id" type="u" direction="out"/>
+ <arg name="action_key" type="s" direction="out"/>
+ </signal>
+ <signal name="dataChanged">
+ <arg name="id" type="u" direction="out"/>
+ </signal>
+ <method name="CloseNotification">
+ <arg name="id" type="u" direction="in"/>
+ </method>
+ <method name="GetServerInformation">
+ <arg name="name" type="s" direction="out"/>
+ <arg name="vendor" type="s" direction="out"/>
+ <arg name="version" type="s" direction="out"/>
+ <arg name="specVersion" type="s" direction="out"/>
+ </method>
+ <method name="GetCapabilities">
+ <arg type="as" direction="out"/>
+ </method>
+ <method name="Notify">
+ <arg type="u" direction="out"/>
+ <arg name="app_name" type="s" direction="in"/>
+ <arg name="replaces_id" type="u" direction="in"/>
+ <arg name="app_icon" type="s" direction="in"/>
+ <arg name="summary" type="s" direction="in"/>
+ <arg name="body" type="s" direction="in"/>
+ <arg name="actions" type="as" direction="in"/>
+ <arg name="hints" type="a{sv}" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In6" value="QVariantMap"/>
+ <arg name="expire_timeout" type="i" direction="in"/>
+ </method>
+ <method name="onDataChanged">
+ <arg name="id" type="u" direction="in"/>
+ </method>
+ <method name="onCompleted">
+ <arg name="id" type="u" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/tests/integration/indicator-sound-test-base.cpp b/tests/integration/indicator-sound-test-base.cpp
index a8d41a0..f9db365 100644
--- a/tests/integration/indicator-sound-test-base.cpp
+++ b/tests/integration/indicator-sound-test-base.cpp
@@ -22,6 +22,7 @@
#include "dbus_properties_interface.h"
#include "dbus_accounts_interface.h"
#include "dbus_accountssound_interface.h"
+#include "dbus_notifications_interface.h"
#include "dbus-types.h"
#include <gio/gio.h>
@@ -42,7 +43,67 @@ IndicatorSoundTestBase::IndicatorSoundTestBase() :
IndicatorSoundTestBase::~IndicatorSoundTestBase()
{
+}
+
+void IndicatorSoundTestBase::SetUp()
+{
+ setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, true);
+ setenv("DBUS_SYSTEM_BUS_ADDRESS", dbusTestRunner.systemBus().toStdString().c_str(), true);
+ setenv("DBUS_SESSION_BUS_ADDRESS", dbusTestRunner.sessionBus().toStdString().c_str(), true);
+ dbusMock.registerNotificationDaemon();
+
+ dbusTestRunner.startServices();
+
+ auto& notifications = notificationsMockInterface();
+ notifications.AddMethod("org.freedesktop.Notifications",
+ "GetCapabilities",
+ "",
+ "as",
+ "ret = ['actions', 'body', 'body-markup', 'icon-static', 'image/svg+xml', 'x-canonical-private-synchronous', 'x-canonical-append', 'x-canonical-private-icon-only', 'x-canonical-truncation', 'private-synchronous', 'append', 'private-icon-only', 'truncation']"
+ ).waitForFinished();
+}
+
+void IndicatorSoundTestBase::TearDown()
+{
+ unsetenv("XDG_DATA_DIRS");
+ unsetenv("PULSE_SERVER");
+ unsetenv("DBUS_SYSTEM_BUS_ADDRESS");
+}
+
+void gvariant_deleter(GVariant* varptr)
+{
+ if (varptr != nullptr)
+ {
+ g_variant_unref(varptr);
+ }
+}
+std::shared_ptr<GVariant> IndicatorSoundTestBase::volume_variant(double volume)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "title",
+ g_variant_new_string("_Sound"));
+
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "accessible-desc",
+ g_variant_new_string("_Sound"));
+
+ auto icon = g_themed_icon_new("icon");
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "icon",
+ g_icon_serialize(icon));
+
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "visible",
+ g_variant_new_boolean(true));
+ return shared_ptr<GVariant>(g_variant_builder_end(&builder), &gvariant_deleter);
}
bool IndicatorSoundTestBase::setStreamRestoreVolume(QString const &role, double volume)
@@ -164,7 +225,8 @@ void IndicatorSoundTestBase::startPulseDesktop()
<< "--system=false"
<< "--exit-idle-time=-1"
<< "-n"
- << "--load=module-null-sink"
+ << QString("--load=module-null-sink sink_name=indicator_sound_test_speaker")
+ << QString("--load=module-null-sink sink_name=indicator_sound_test_headphones")
<< "--log-target=file:/tmp/pulse-daemon.log"
<< "--load=module-dbus-protocol"
<< "--load=module-native-protocol-tcp auth-ip-acl=127.0.0.1"
@@ -194,7 +256,8 @@ void IndicatorSoundTestBase::startPulsePhone()
<< "--system=false"
<< "--exit-idle-time=-1"
<< "-n"
- << "--load=module-null-sink"
+ << QString("--load=module-null-sink sink_name=indicator_sound_test_speaker")
+ << QString("--load=module-null-sink sink_name=indicator_sound_test_headphones")
<< "--log-target=file:/tmp/pulse-daemon.log"
<< QString("--load=module-stream-restore restore_device=false restore_muted=false fallback_table=%1").arg(STREAM_RESTORE_TABLE)
<< "--load=module-dbus-protocol"
@@ -264,55 +327,6 @@ mh::MenuMatcher::Parameters IndicatorSoundTestBase::phoneParameters()
"/com/canonical/indicator/sound/phone");
}
-void IndicatorSoundTestBase::SetUp()
-{
- setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, true);
- setenv("DBUS_SYSTEM_BUS_ADDRESS", dbusTestRunner.systemBus().toStdString().c_str(), true);
-}
-
-void IndicatorSoundTestBase::TearDown()
-{
- unsetenv("XDG_DATA_DIRS");
- unsetenv("PULSE_SERVER");
- unsetenv("DBUS_SYSTEM_BUS_ADDRESS");
-}
-
-void gvariant_deleter(GVariant* varptr)
-{
- if (varptr != nullptr)
- {
- g_variant_unref(varptr);
- }
-}
-
-std::shared_ptr<GVariant> IndicatorSoundTestBase::volume_variant(double volume)
-{
- GVariantBuilder builder;
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add(&builder,
- "{sv}",
- "title",
- g_variant_new_string("_Sound"));
-
- g_variant_builder_add(&builder,
- "{sv}",
- "accessible-desc",
- g_variant_new_string("_Sound"));
-
- auto icon = g_themed_icon_new("icon");
- g_variant_builder_add(&builder,
- "{sv}",
- "icon",
- g_icon_serialize(icon));
-
- g_variant_builder_add(&builder,
- "{sv}",
- "visible",
- g_variant_new_boolean(true));
- return shared_ptr<GVariant>(g_variant_builder_end(&builder), &gvariant_deleter);
-}
-
unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::volumeSlider(double volume)
{
return mh::MenuItemMatcher().radio()
@@ -409,3 +423,206 @@ void IndicatorSoundTestBase::initializeAccountsInterface()
}
}
}
+
+OrgFreedesktopDBusMockInterface& IndicatorSoundTestBase::notificationsMockInterface()
+{
+ return dbusMock.mockInterface("org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ "org.freedesktop.Notifications",
+ QDBusConnection::SessionBus);
+}
+
+bool IndicatorSoundTestBase::setActionValue(const QString & action, QVariant value)
+{
+ QDBusInterface actionsInterface(DBusTypes::DBUS_NAME,
+ DBusTypes::MAIN_SERVICE_PATH,
+ DBusTypes::ACTIONS_INTERFACE,
+ dbusTestRunner.sessionConnection());
+
+ QDBusVariant dbusVar(value);
+ auto resp = actionsInterface.call("SetState",
+ action,
+ QVariant::fromValue(dbusVar),
+ QVariant::fromValue(QVariantMap()));
+
+ if (resp.type() == QDBusMessage::ErrorMessage)
+ {
+ qCritical() << "IndicatorSoundTestBase::setActionValue(): Failed to set value for action "
+ << action
+ << " "
+ << resp.errorMessage();
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool IndicatorSoundTestBase::pressNotificationButton(int id, const QString & button)
+{
+ OrgFreedesktopDBusMockInterface actionsInterface("org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ dbusTestRunner.sessionConnection());
+
+ actionsInterface.EmitSignal(
+ "org.freedesktop.Notifications",
+ "ActionInvoked", "us", QVariantList() << id << button);
+
+ return true;
+}
+
+bool IndicatorSoundTestBase::qDBusArgumentToMap(QVariant const& variant, QVariantMap& map)
+{
+ if (variant.canConvert<QDBusArgument>())
+ {
+ QDBusArgument value(variant.value<QDBusArgument>());
+ if (value.currentType() == QDBusArgument::MapType)
+ {
+ value >> map;
+ return true;
+ }
+ }
+ return false;
+}
+
+void IndicatorSoundTestBase::checkVolumeNotification(double volume, QString const& label, bool isLoud, QVariantList call)
+{
+ QString icon;
+ if (volume <= 0.0)
+ {
+ icon = "audio-volume-muted";
+ }
+ else if (volume <= 0.3)
+ {
+ icon = "audio-volume-low";
+ }
+ else if (volume <= 0.7)
+ {
+ icon = "audio-volume-medium";
+ }
+ else
+ {
+ icon = "audio-volume-high";
+ }
+
+ ASSERT_NE(call.size(), 0);
+ EXPECT_EQ("Notify", call.at(0));
+
+ QVariantList const& args(call.at(1).toList());
+ ASSERT_EQ(8, args.size());
+ EXPECT_EQ("indicator-sound", args.at(0));
+ EXPECT_EQ(icon, args.at(2));
+ EXPECT_EQ("Volume", args.at(3));
+ EXPECT_EQ(label, args.at(4));
+ EXPECT_EQ(QStringList(), args.at(5));
+
+ QVariantMap hints;
+ ASSERT_TRUE(qDBusArgumentToMap(args.at(6), hints));
+ ASSERT_TRUE(hints.contains("value"));
+ ASSERT_TRUE(hints.contains("x-canonical-non-shaped-icon"));
+ ASSERT_TRUE(hints.contains("x-canonical-value-bar-tint"));
+ ASSERT_TRUE(hints.contains("x-canonical-private-synchronous"));
+
+ EXPECT_EQ(volume*100, hints["value"]);
+ EXPECT_EQ(true, hints["x-canonical-non-shaped-icon"]);
+ EXPECT_EQ(isLoud, hints["x-canonical-value-bar-tint"]);
+ EXPECT_EQ(true, hints["x-canonical-private-synchronous"]);
+}
+
+void IndicatorSoundTestBase::checkHighVolumeNotification(QVariantList call)
+{
+ ASSERT_NE(call.size(), 0);
+ EXPECT_EQ("Notify", call.at(0));
+
+ QVariantList const& args(call.at(1).toList());
+ ASSERT_EQ(8, args.size());
+ EXPECT_EQ("indicator-sound", args.at(0));
+ EXPECT_EQ("Volume", args.at(3));
+}
+
+void IndicatorSoundTestBase::checkCloseNotification(int id, QVariantList call)
+{
+ EXPECT_EQ("CloseNotification", call.at(0));
+ QVariantList const& args(call.at(1).toList());
+ ASSERT_EQ(1, args.size());
+}
+
+void IndicatorSoundTestBase::checkNotificationWithNoArgs(QString const& method, QVariantList call)
+{
+ EXPECT_EQ(method, call.at(0));
+ QVariantList const& args(call.at(1).toList());
+ ASSERT_EQ(0, args.size());
+}
+
+int IndicatorSoundTestBase::getNotificationID(QVariantList call)
+{
+ if (call.size() == 0)
+ {
+ return -1;
+ }
+ QVariantList const& args(call.at(1).toList());
+ if (args.size() != 8)
+ {
+ return -1;
+ }
+ if (args.at(0) != "indicator-sound")
+ {
+ return -1;
+ }
+
+ bool isInt;
+ int id = args.at(1).toInt(&isInt);
+ if (!isInt)
+ {
+ return -1;
+ }
+ return id;
+}
+
+bool IndicatorSoundTestBase::activateHeadphones(bool headphonesActive)
+{
+ QProcess pacltProcess;
+
+ QString defaultSinkName = "indicator_sound_test_speaker";
+ QString suspendedSinkName = "indicator_sound_test_headphones";
+ if (headphonesActive)
+ {
+ defaultSinkName = "indicator_sound_test_headphones";
+ suspendedSinkName = "indicator_sound_test_speaker";
+ }
+
+ pacltProcess.start("pactl", QStringList() << "-s"
+ << "127.0.0.1"
+ << "set-default-sink"
+ << defaultSinkName);
+ if (!pacltProcess.waitForStarted())
+ return false;
+
+ if (!pacltProcess.waitForFinished())
+ return false;
+
+ pacltProcess.start("pactl", QStringList() << "-s"
+ << "127.0.0.1"
+ << "suspend-sink"
+ << defaultSinkName
+ << "0");
+ if (!pacltProcess.waitForStarted())
+ return false;
+
+ if (!pacltProcess.waitForFinished())
+ return false;
+
+ pacltProcess.start("pactl", QStringList() << "-s"
+ << "127.0.0.1"
+ << "suspend-sink"
+ << suspendedSinkName
+ << "1");
+ if (!pacltProcess.waitForStarted())
+ return false;
+
+ if (!pacltProcess.waitForFinished())
+ return false;
+
+ return pacltProcess.exitCode() == 0;
+}
diff --git a/tests/integration/indicator-sound-test-base.h b/tests/integration/indicator-sound-test-base.h
index 0dc0052..20e44fc 100644
--- a/tests/integration/indicator-sound-test-base.h
+++ b/tests/integration/indicator-sound-test-base.h
@@ -33,6 +33,15 @@ class DBusPulseVolume;
class DBusPropertiesInterface;
class QSignalSpy;
+#define WAIT_FOR_SIGNALS(signalSpy, signalsExpected)\
+{\
+ while (signalSpy.size() < signalsExpected)\
+ {\
+ ASSERT_TRUE(signalSpy.wait());\
+ }\
+ ASSERT_EQ(signalsExpected, signalSpy.size());\
+}
+
class IndicatorSoundTestBase: public testing::Test
{
public:
@@ -81,6 +90,26 @@ protected:
void initializeAccountsInterface();
+ OrgFreedesktopDBusMockInterface& notificationsMockInterface();
+
+ bool setActionValue(const QString & action, QVariant value);
+
+ bool pressNotificationButton(int id, const QString & button);
+
+ bool qDBusArgumentToMap(QVariant const& variant, QVariantMap& map);
+
+ void checkVolumeNotification(double volume, QString const& label, bool isLoud, QVariantList call);
+
+ void checkHighVolumeNotification(QVariantList call);
+
+ void checkCloseNotification(int id, QVariantList call);
+
+ void checkNotificationWithNoArgs(QString const& method, QVariantList call);
+
+ int getNotificationID(QVariantList call);
+
+ bool activateHeadphones(bool headphonesActive);
+
QtDBusTest::DBusTestRunner dbusTestRunner;
QtDBusMock::DBusMock dbusMock;
diff --git a/tests/integration/test-indicator.cpp b/tests/integration/test-indicator.cpp
index 5a4b4ee..1607367 100644
--- a/tests/integration/test-indicator.cpp
+++ b/tests/integration/test-indicator.cpp
@@ -634,4 +634,292 @@ TEST_F(TestIndicator, DesktopChangeRoleVolume)
).match());
}
+TEST_F(TestIndicator, PhoneNotificationVolume)
+{
+ double INITIAL_VOLUME = 0.0;
+
+ QSignalSpy notificationsSpy(&notificationsMockInterface(),
+ SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+
+ ASSERT_NO_THROW(startAccountsService());
+ EXPECT_TRUE(clearGSettingsPlayers());
+ ASSERT_NO_THROW(startPulsePhone());
+
+ // initialize volumes in pulseaudio
+ EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME));
+
+ // start now the indicator, so it picks the new volumes
+ ASSERT_NO_THROW(startIndicator());
+
+ // check the initial state
+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
+ .item(mh::MenuItemMatcher()
+ .action("indicator.root")
+ .string_attribute("x-canonical-type", "com.canonical.indicator.root")
+ .string_attribute("x-canonical-scroll-action", "indicator.scroll")
+ .string_attribute("x-canonical-secondary-action", "indicator.mute")
+ .string_attribute("submenu-action", "indicator.indicator-shown")
+ .mode(mh::MenuItemMatcher::Mode::all)
+ .submenu()
+ .item(mh::MenuItemMatcher()
+ .section()
+ .item(silentModeSwitch(false))
+ .item(volumeSlider(INITIAL_VOLUME))
+ )
+ .item(mh::MenuItemMatcher()
+ .label("Sound Settingsā€¦")
+ .action("indicator.phone-settings")
+ )
+ ).match());
+
+ // change volume to 1.0
+ setActionValue("volume", QVariant::fromValue(1.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 3);
+
+ // the first time we also have the calls to
+ // GetServerInformation and GetCapabilities
+ checkNotificationWithNoArgs("GetServerInformation", notificationsSpy.at(0));
+ checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(1));
+ checkVolumeNotification(1.0, "", false, notificationsSpy.at(2));
+
+ notificationsSpy.clear();
+ setActionValue("volume", QVariant::fromValue(0.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 1)
+
+ checkVolumeNotification(0.0, "", false, notificationsSpy.at(0));
+
+ notificationsSpy.clear();
+ setActionValue("volume", QVariant::fromValue(0.5));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 1)
+
+ checkVolumeNotification(0.5, "", false, notificationsSpy.at(0));
+}
+
+TEST_F(TestIndicator, PhoneNotificationWarningVolume)
+{
+ double INITIAL_VOLUME = 0.0;
+
+ QSignalSpy notificationsSpy(&notificationsMockInterface(),
+ SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+
+ ASSERT_NO_THROW(startAccountsService());
+ ASSERT_NO_THROW(startPulsePhone());
+
+ // initialize volumes in pulseaudio
+ EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME));
+ EXPECT_TRUE(setStreamRestoreVolume("multimedia", INITIAL_VOLUME));
+
+ // start now the indicator, so it picks the new volumes
+ ASSERT_NO_THROW(startIndicator());
+
+ // activate the headphones
+ EXPECT_TRUE(activateHeadphones(true));
+
+ // set an initial volume to the alert role
+ setStreamRestoreVolume("alert", 1.0);
+ EXPECT_TRUE(waitVolumeChangedInIndicator());
+
+ // play a test sound, it should change the role in the indicator
+ EXPECT_TRUE(startTestSound("multimedia"));
+ EXPECT_TRUE(waitVolumeChangedInIndicator());
+
+ // change volume to 0.0... no warning should be emitted
+ setActionValue("volume", QVariant::fromValue(0.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 3);
+
+ // the first time we also have the calls to
+ // GetServerInformation and GetCapabilities
+ checkNotificationWithNoArgs("GetServerInformation", notificationsSpy.at(0));
+ checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(1));
+ checkVolumeNotification(0.0, "", false, notificationsSpy.at(2));
+ notificationsSpy.clear();
+
+ // change volume to 0.5... no warning should be emitted
+ setActionValue("volume", QVariant::fromValue(0.5));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 1);
+
+ checkVolumeNotification(0.5, "", false, notificationsSpy.at(0));
+ notificationsSpy.clear();
+
+ // change volume to 1.0... warning should be emitted
+ setActionValue("volume", QVariant::fromValue(1.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 4);
+
+ // the notification is sent twice (TODO check why)
+ checkCloseNotification(1, notificationsSpy.at(0));
+ checkHighVolumeNotification(notificationsSpy.at(1));
+ checkCloseNotification(1, notificationsSpy.at(2));
+ checkHighVolumeNotification(notificationsSpy.at(3));
+
+ // get the last notification ID
+ int idNotification = getNotificationID(notificationsSpy.at(3));
+ ASSERT_NE(-1, idNotification);
+
+ qWarning() << "XGM: id Notification: " << idNotification;
+
+ // cancel the dialog
+ pressNotificationButton(idNotification, "cancel");
+
+ // check that the volume was clamped
+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
+ .item(mh::MenuItemMatcher()
+ .action("indicator.root")
+ .string_attribute("x-canonical-type", "com.canonical.indicator.root")
+ .string_attribute("x-canonical-scroll-action", "indicator.scroll")
+ .string_attribute("x-canonical-secondary-action", "indicator.mute")
+ .string_attribute("submenu-action", "indicator.indicator-shown")
+ .mode(mh::MenuItemMatcher::Mode::starts_with)
+ .submenu()
+ .item(mh::MenuItemMatcher()
+ .section()
+ .item(silentModeSwitch(false))
+ .item(volumeSlider(0.74))
+ )
+ ).match());
+
+ // try again...
+ notificationsSpy.clear();
+ // change volume to 1.0... warning should be emitted
+ setActionValue("volume", QVariant::fromValue(1.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 4);
+
+ checkCloseNotification(1, notificationsSpy.at(0));
+ checkHighVolumeNotification(notificationsSpy.at(1));
+ checkCloseNotification(1, notificationsSpy.at(2));
+ checkHighVolumeNotification(notificationsSpy.at(3));
+
+ // get the last notification ID
+ idNotification = getNotificationID(notificationsSpy.at(3));
+ ASSERT_NE(-1, idNotification);
+
+ qWarning() << "XGM: id Notification: " << idNotification;
+
+ // this time we approve
+ pressNotificationButton(idNotification, "ok");
+
+ // check that the volume was applied
+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
+ .item(mh::MenuItemMatcher()
+ .action("indicator.root")
+ .string_attribute("x-canonical-type", "com.canonical.indicator.root")
+ .string_attribute("x-canonical-scroll-action", "indicator.scroll")
+ .string_attribute("x-canonical-secondary-action", "indicator.mute")
+ .string_attribute("submenu-action", "indicator.indicator-shown")
+ .mode(mh::MenuItemMatcher::Mode::starts_with)
+ .submenu()
+ .item(mh::MenuItemMatcher()
+ .section()
+ .item(silentModeSwitch(false))
+ .item(volumeSlider(1.0))
+ .item(mh::MenuItemMatcher()
+ .action("indicator.high-volume-warning-item")
+ .label("High volume can damage your hearing.")
+ )
+ )
+ ).match());
+
+ // after the warning was approved we should be able to modify the volume
+ // and don't get the warning
+ notificationsSpy.clear();
+
+ // change volume to 0.5... no warning should be emitted
+ setActionValue("volume", QVariant::fromValue(0.5));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 2);
+
+ // check the notification TODO check why the sound indicator sends it twice
+ checkVolumeNotification(0.5, "", false, notificationsSpy.at(0));
+ checkVolumeNotification(0.5, "", false, notificationsSpy.at(1));
+
+ // check that the volume was applied
+ // and that we don't have the warning item
+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
+ .item(mh::MenuItemMatcher()
+ .action("indicator.root")
+ .string_attribute("x-canonical-type", "com.canonical.indicator.root")
+ .string_attribute("x-canonical-scroll-action", "indicator.scroll")
+ .string_attribute("x-canonical-secondary-action", "indicator.mute")
+ .string_attribute("submenu-action", "indicator.indicator-shown")
+ .mode(mh::MenuItemMatcher::Mode::starts_with)
+ .submenu()
+ .item(mh::MenuItemMatcher()
+ .section()
+ .item(silentModeSwitch(false))
+ .item(volumeSlider(0.5))
+ )
+ ).match());
+
+ // now set high volume again, we should not get the warning dialog
+ // as we already approved it
+ notificationsSpy.clear();
+
+ setActionValue("volume", QVariant::fromValue(1.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 2);
+
+ // check the notification TODO check why the sound indicator sends it twice
+ checkVolumeNotification(1.0, "High volume can damage your hearing.", true, notificationsSpy.at(0));
+ checkVolumeNotification(1.0, "High volume can damage your hearing.", true, notificationsSpy.at(1));
+}
+
+TEST_F(TestIndicator, PhoneNotificationWarningVolumeAlertMode)
+{
+ double INITIAL_VOLUME = 0.0;
+
+ QSignalSpy notificationsSpy(&notificationsMockInterface(),
+ SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+
+ ASSERT_NO_THROW(startAccountsService());
+ ASSERT_NO_THROW(startPulsePhone());
+
+ // initialize volumes in pulseaudio
+ EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME));
+ EXPECT_TRUE(setStreamRestoreVolume("multimedia", INITIAL_VOLUME));
+
+ // start now the indicator, so it picks the new volumes
+ ASSERT_NO_THROW(startIndicator());
+
+ // activate the headphones
+ EXPECT_TRUE(activateHeadphones(true));
+
+ // set an initial volume to the alert role
+ setStreamRestoreVolume("alert", 1.0);
+ EXPECT_TRUE(waitVolumeChangedInIndicator());
+
+ // change volume to 0.0... no warning should be emitted
+ setActionValue("volume", QVariant::fromValue(0.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 3);
+
+ // the first time we also have the calls to
+ // GetServerInformation and GetCapabilities
+ checkNotificationWithNoArgs("GetServerInformation", notificationsSpy.at(0));
+ checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(1));
+ checkVolumeNotification(0.0, "", false, notificationsSpy.at(2));
+ notificationsSpy.clear();
+
+ // change volume to 0.5... no warning should be emitted
+ setActionValue("volume", QVariant::fromValue(0.5));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 1);
+
+ checkVolumeNotification(0.5, "", false, notificationsSpy.at(0));
+ notificationsSpy.clear();
+
+ // change volume to 1.0... no warning should be emitted, we are in alert mode
+ setActionValue("volume", QVariant::fromValue(1.0));
+
+ WAIT_FOR_SIGNALS(notificationsSpy, 1);
+
+ checkVolumeNotification(1.0, "", false, notificationsSpy.at(0));
+ notificationsSpy.clear();
+}
+
} // namespace