Merge lp:~morphis/aethercast/input-provider-support into lp:aethercast

Proposed by Simon Fels
Status: Needs review
Proposed branch: lp:~morphis/aethercast/input-provider-support
Merge into: lp:aethercast
Diff against target: 1174 lines (+872/-9)
26 files modified
CMakeLists.txt (+1/-0)
data/org.aethercast.xml (+15/-0)
docs/input-provider.txt (+2/-2)
src/CMakeLists.txt (+5/-0)
src/mcs/dbus_types.h (+31/-0)
src/mcs/forwardingmiracastcontroller.cpp (+12/-0)
src/mcs/forwardingmiracastcontroller.h (+4/-0)
src/mcs/inputeventchannel.cpp (+123/-0)
src/mcs/inputeventchannel.h (+74/-0)
src/mcs/inputprovider.cpp (+18/-0)
src/mcs/inputprovider.h (+46/-0)
src/mcs/inputproviderstub.cpp (+137/-0)
src/mcs/inputproviderstub.h (+67/-0)
src/mcs/miracastcontroller.cpp (+16/-0)
src/mcs/miracastcontroller.h (+5/-0)
src/mcs/miracastcontrollerskeleton.cpp (+66/-3)
src/mcs/miracastcontrollerskeleton.h (+8/-4)
src/mcs/miracastservice.cpp (+16/-0)
src/mcs/miracastservice.h (+7/-0)
src/mcs/withdelegate.cpp (+16/-0)
src/mcs/withdelegate.h (+37/-0)
tests/mcs/CMakeLists.txt (+8/-0)
tests/mcs/forwardingmiracastcontroller_tests.cpp (+10/-0)
tests/mcs/inputeventchannel_tests.cpp (+66/-0)
tests/mcs/miracastcontrollerskeleton_tests.cpp (+4/-0)
tests/mcs/miracastservice_tests.cpp (+78/-0)
To merge this branch: bzr merge lp:~morphis/aethercast/input-provider-support
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Simon Fels Needs Fixing
Review via email: mp+280746@code.launchpad.net

Description of the change

Add input provider support

To post a comment you must log in.
Revision history for this message
Simon Fels (morphis) wrote :

Still WIP.

review: Needs Fixing
119. By Simon Fels

Merge trunk

120. By Simon Fels

Fix problems after merge

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:120
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/input-provider-support/+merge/280746/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/15/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/15
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/15
        deb: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/15/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/15

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/15/rebuild

review: Needs Fixing (continuous-integration)
121. By Simon Fels

Wrap input provider into service and add channel implementation + tests

122. By Simon Fels

Fix ForwardingMiracastController tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:122
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/input-provider-support/+merge/280746/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/16/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/16/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/16/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/16/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/16/rebuild

review: Needs Fixing (continuous-integration)
123. By Simon Fels

Correct InputEventChannel unit tests to pass fully

124. By Simon Fels

Process real input events

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:124
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/input-provider-support/+merge/280746/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/17/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/17
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/17
        deb: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/17/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/17

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/17/rebuild

review: Needs Fixing (continuous-integration)
125. By Simon Fels

Properly register input provider

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:125
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~morphis/aethercast/input-provider-support/+merge/280746/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/aethercast-ci/18/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-amd64-ci/18
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/18
        deb: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-armhf-ci/18/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/aethercast-vivid-i386-ci/18

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/aethercast-ci/18/rebuild

review: Needs Fixing (continuous-integration)

Unmerged revisions

125. By Simon Fels

Properly register input provider

124. By Simon Fels

Process real input events

123. By Simon Fels

Correct InputEventChannel unit tests to pass fully

122. By Simon Fels

Fix ForwardingMiracastController tests

121. By Simon Fels

Wrap input provider into service and add channel implementation + tests

120. By Simon Fels

Fix problems after merge

119. By Simon Fels

Merge trunk

118. By Simon Fels

First part of input provider infrastructure

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-12-10 06:47:03 +0000
3+++ CMakeLists.txt 2015-12-18 16:38:21 +0000
4@@ -64,6 +64,7 @@
5 pkg_check_modules(GST REQUIRED gstreamer-1.0)
6 pkg_check_modules(WDS REQUIRED wds)
7 pkg_check_modules(READLINE readline)
8+
9 # Build with system gmock and embedded gtest
10 set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory")
11 set (GMOCK_SOURCE_DIR "/usr/src/gmock" CACHE PATH "gmock source directory")
12
13=== modified file 'data/org.aethercast.xml'
14--- data/org.aethercast.xml 2015-12-10 17:13:50 +0000
15+++ data/org.aethercast.xml 2015-12-18 16:38:21 +0000
16@@ -9,10 +9,25 @@
17 <arg name="path" type="o" direction="in"/>
18 </method>
19 <method name="Scan"/>
20+ <method name="RegisterInputProvider">
21+ <arg name="path" type="o" direction="in"/>
22+ <arg name="options" type="a{sv}" direction="in"/>
23+ </method>
24+ <method name="UnregisterInputProvider">
25+ <arg name="path" type="o" direction="in"/>
26+ </method>
27 <property name="State" type="s" access="read"/>
28 <property name="Capabilities" type="as" access="read"/>
29 <property name="Scanning" type="b" access="read"/>
30 </interface>
31+ <interface name="org.aethercast.InputProvider">
32+ <method name="NewConnection">
33+ <arg name="fd" type="h" direction="in"/>
34+ <arg name="options" type="a{sv}" direction="in"/>
35+ </method>
36+ <method name="RequestDisconnection"/>
37+ <property name="cursor" type="s" access="read"/>
38+ </interface>
39 <interface name="org.aethercast.Device">
40 <method name="Connect">
41 <arg name="role" type="s" direction="in"/>
42
43=== modified file 'docs/input-provider.txt'
44--- docs/input-provider.txt 2015-12-16 11:54:08 +0000
45+++ docs/input-provider.txt 2015-12-18 16:38:21 +0000
46@@ -43,7 +43,7 @@
47 This method gets called when the input provider is
48 unregistered and can be used to perform cleanup tasks.
49
50- void NewConnection(object device, fd, dict options)
51+ void NewConnection(fd, dict options)
52
53 This methods gets called when a connection to a remote
54 display is established.
55@@ -51,7 +51,7 @@
56 Possible errors: org.aethercast.Error.Rejected
57 org.aethercast.Error.Canceled
58
59- void RequestDisconnection(object device)
60+ void RequestDisconnection()
61
62 This methods gets called when a device gets disconnected.
63
64
65=== modified file 'src/CMakeLists.txt'
66--- src/CMakeLists.txt 2015-12-12 20:22:35 +0000
67+++ src/CMakeLists.txt 2015-12-18 16:38:21 +0000
68@@ -17,9 +17,12 @@
69 mcs/keep_alive.h
70 mcs/mac_address.h
71 mcs/types.h
72+ mcs/dbus_types.h
73 )
74
75 set(SOURCES
76+ mcs/withdelegate.cpp
77+ mcs/inputeventchannel.cpp
78 mcs/utils.cpp
79 mcs/networkutils.cpp
80 mcs/mediamanagerfactory.cpp
81@@ -37,10 +40,12 @@
82 mcs/networkmanager.cpp
83 mcs/networkmanagerfactory.cpp
84 mcs/networkdevice.cpp
85+ mcs/inputprovider.cpp
86
87 ${CMAKE_CURRENT_BINARY_DIR}/mcs/aethercastinterface.c
88 mcs/dbushelpers.cpp
89 mcs/networkdeviceadapter.cpp
90+ mcs/inputproviderstub.cpp
91
92 wpa/gdhcp/common.c
93 wpa/gdhcp/ipv4ll.c
94
95=== added file 'src/mcs/dbus_types.h'
96--- src/mcs/dbus_types.h 1970-01-01 00:00:00 +0000
97+++ src/mcs/dbus_types.h 2015-12-18 16:38:21 +0000
98@@ -0,0 +1,31 @@
99+/*
100+ * Copyright (C) 2015 Canonical, Ltd.
101+ *
102+ * This program is free software: you can redistribute it and/or modify it
103+ * under the terms of the GNU General Public License version 3, as published
104+ * by the Free Software Foundation.
105+ *
106+ * This program is distributed in the hope that it will be useful, but
107+ * WITHOUT ANY WARRANTY; without even the implied warranties of
108+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
109+ * PURPOSE. See the GNU General Public License for more details.
110+ *
111+ * You should have received a copy of the GNU General Public License along
112+ * with this program. If not, see <http://www.gnu.org/licenses/>.
113+ *
114+ */
115+
116+#ifndef DBUS_TYPES_H_
117+#define DBUS_TYPES_H_
118+
119+#include <string>
120+
121+namespace mcs {
122+namespace dbus {
123+
124+typedef std::string ObjectPath;
125+
126+} // namespace dbus
127+} // namespace mcs
128+
129+#endif
130
131=== modified file 'src/mcs/forwardingmiracastcontroller.cpp'
132--- src/mcs/forwardingmiracastcontroller.cpp 2015-12-11 22:02:52 +0000
133+++ src/mcs/forwardingmiracastcontroller.cpp 2015-12-18 16:38:21 +0000
134@@ -57,4 +57,16 @@
135 bool ForwardingMiracastController::Scanning() const {
136 return fwd_->Scanning();
137 }
138+
139+bool ForwardingMiracastController::HasInputProvider() const {
140+ return fwd_->HasInputProvider();
141+}
142+
143+void ForwardingMiracastController::SetInputProvider(const InputProvider::Ptr &provider) {
144+ fwd_->SetInputProvider(provider);
145+}
146+
147+void ForwardingMiracastController::ResetInputProvider() {
148+ fwd_->ResetInputProvider();
149+}
150 }
151
152=== modified file 'src/mcs/forwardingmiracastcontroller.h'
153--- src/mcs/forwardingmiracastcontroller.h 2015-12-11 22:02:52 +0000
154+++ src/mcs/forwardingmiracastcontroller.h 2015-12-18 16:38:21 +0000
155@@ -38,6 +38,10 @@
156 virtual std::vector<NetworkDeviceRole> SupportedRoles() const override;
157 virtual bool Scanning() const override;
158
159+ virtual bool HasInputProvider() const;
160+ virtual void SetInputProvider(const InputProvider::Ptr &provider);
161+ virtual void ResetInputProvider();
162+
163 private:
164 MiracastController::Ptr fwd_;
165 };
166
167=== added file 'src/mcs/inputeventchannel.cpp'
168--- src/mcs/inputeventchannel.cpp 1970-01-01 00:00:00 +0000
169+++ src/mcs/inputeventchannel.cpp 2015-12-18 16:38:21 +0000
170@@ -0,0 +1,123 @@
171+/*
172+ * Copyright (C) 2015 Canonical, Ltd.
173+ *
174+ * This program is free software: you can redistribute it and/or modify it
175+ * under the terms of the GNU General Public License version 3, as published
176+ * by the Free Software Foundation.
177+ *
178+ * This program is distributed in the hope that it will be useful, but
179+ * WITHOUT ANY WARRANTY; without even the implied warranties of
180+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
181+ * PURPOSE. See the GNU General Public License for more details.
182+ *
183+ * You should have received a copy of the GNU General Public License along
184+ * with this program. If not, see <http://www.gnu.org/licenses/>.
185+ *
186+ */
187+
188+#include <unistd.h>
189+#include <sys/types.h>
190+#include <sys/socket.h>
191+#include <fcntl.h>
192+#include <linux/input.h>
193+
194+#include "inputeventchannel.h"
195+#include "keep_alive.h"
196+#include "logger.h"
197+
198+namespace mcs {
199+
200+std::ostream& operator<<(std::ostream& out, const InputEvent& e)
201+{
202+ return out << "["
203+ << e.when.count() << " "
204+ << e.type << " "
205+ << e.code << " "
206+ << e.value
207+ << "]";
208+}
209+
210+InputEventChannel::InputEventChannel() :
211+ local_fd_(0),
212+ remote_fd_(0),
213+ channel_(nullptr),
214+ channel_watch_(0) {
215+}
216+
217+InputEventChannel::~InputEventChannel() {
218+ if (channel_watch_ > 0)
219+ g_source_remove(channel_watch_);
220+
221+ if (channel_)
222+ g_io_channel_unref(channel_);
223+
224+ if (local_fd_ > 0)
225+ ::close(local_fd_);
226+
227+ if (remote_fd_ > 0)
228+ ::close(remote_fd_);
229+}
230+
231+std::shared_ptr<InputEventChannel> InputEventChannel::Create() {
232+ return std::shared_ptr<InputEventChannel>(new InputEventChannel)->FinalizeConstruction();
233+}
234+
235+InputEvent InputEventChannel::ReadNextEvent() {
236+ struct input_event ev;
237+
238+ ssize_t bytes_read = ::read(local_fd_, &ev, sizeof(ev));
239+ if (bytes_read <= 0)
240+ return InputEvent{};
241+
242+ return InputEvent{std::chrono::milliseconds(0), ev.type, ev.code, ev.value};
243+}
244+
245+gboolean InputEventChannel::OnActivity(GIOChannel *channel, GIOCondition condition, gpointer user_data) {
246+ auto inst = static_cast<WeakKeepAlive<InputEventChannel>*>(user_data)->GetInstance().lock();
247+
248+ if (condition & G_IO_HUP) {
249+ if (auto sp = inst->delegate_.lock())
250+ sp->OnChannelClosed();
251+
252+ return TRUE;
253+ }
254+
255+ auto event = inst->ReadNextEvent();
256+
257+ if (auto sp = inst->delegate_.lock())
258+ sp->OnEvent(event);
259+
260+ return TRUE;
261+}
262+
263+std::shared_ptr<InputEventChannel> InputEventChannel::FinalizeConstruction() {
264+ auto sp = shared_from_this();
265+
266+ int endpoints[2] = {0, 0};
267+
268+ if (::socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, endpoints) < 0) {
269+ ERROR("Failed to create socket pair");
270+ return sp;
271+ }
272+
273+ local_fd_ = endpoints[0];
274+ remote_fd_ = endpoints[1];
275+
276+ channel_ = g_io_channel_unix_new(local_fd_);
277+ channel_watch_ = g_io_add_watch_full(channel_, 0, (GIOCondition) (G_IO_IN | G_IO_HUP | G_IO_ERR),
278+ &InputEventChannel::OnActivity,
279+ new WeakKeepAlive<InputEventChannel>{sp},
280+ [](gpointer data) { delete static_cast<WeakKeepAlive<InputEventChannel>*>(data); });
281+ if (channel_watch_ == 0) {
282+ ERROR("Failed to input channel watch");
283+ return sp;
284+ }
285+
286+ return sp;
287+}
288+
289+int InputEventChannel::RemoteEndpoint() {
290+ return remote_fd_;
291+}
292+
293+} // namespace mcs
294
295=== added file 'src/mcs/inputeventchannel.h'
296--- src/mcs/inputeventchannel.h 1970-01-01 00:00:00 +0000
297+++ src/mcs/inputeventchannel.h 2015-12-18 16:38:21 +0000
298@@ -0,0 +1,74 @@
299+/*
300+ * Copyright (C) 2015 Canonical, Ltd.
301+ *
302+ * This program is free software: you can redistribute it and/or modify it
303+ * under the terms of the GNU General Public License version 3, as published
304+ * by the Free Software Foundation.
305+ *
306+ * This program is distributed in the hope that it will be useful, but
307+ * WITHOUT ANY WARRANTY; without even the implied warranties of
308+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
309+ * PURPOSE. See the GNU General Public License for more details.
310+ *
311+ * You should have received a copy of the GNU General Public License along
312+ * with this program. If not, see <http://www.gnu.org/licenses/>.
313+ *
314+ */
315+
316+#ifndef INPUTEVENTCHANNEL_H_
317+#define INPUTEVENTCHANNEL_H_
318+
319+#include <glib.h>
320+
321+#include <memory>
322+#include <chrono>
323+
324+#include "non_copyable.h"
325+#include "withdelegate.h"
326+
327+namespace mcs {
328+
329+struct InputEvent {
330+ std::chrono::milliseconds when;
331+ std::uint16_t type;
332+ std::uint16_t code;
333+ std::uint32_t value;
334+};
335+
336+std::ostream& operator<<(std::ostream& out, const InputEvent& e);
337+
338+class InputEventChannelDelegate : public mcs::NonCopyable {
339+public:
340+ virtual ~InputEventChannelDelegate() { }
341+ virtual void OnChannelClosed() = 0;
342+ virtual void OnEvent(const InputEvent &event) = 0;
343+};
344+
345+class InputEventChannel : public std::enable_shared_from_this<InputEventChannel>,
346+ public mcs::WithDelegate<InputEventChannelDelegate> {
347+public:
348+ static std::shared_ptr<InputEventChannel> Create();
349+
350+ ~InputEventChannel();
351+
352+ int RemoteEndpoint();
353+
354+private:
355+ InputEventChannel();
356+ std::shared_ptr<InputEventChannel> FinalizeConstruction();
357+
358+ InputEvent ReadNextEvent();
359+
360+private:
361+ static gboolean OnActivity(GIOChannel *channel, GIOCondition condition, gpointer user_data);
362+
363+private:
364+ int local_fd_;
365+ int remote_fd_;
366+ GIOChannel *channel_;
367+ guint channel_watch_;
368+};
369+
370+} // namespace mcs
371+
372+#endif
373
374=== added file 'src/mcs/inputprovider.cpp'
375--- src/mcs/inputprovider.cpp 1970-01-01 00:00:00 +0000
376+++ src/mcs/inputprovider.cpp 2015-12-18 16:38:21 +0000
377@@ -0,0 +1,18 @@
378+/*
379+ * Copyright (C) 2015 Canonical, Ltd.
380+ *
381+ * This program is free software: you can redistribute it and/or modify it
382+ * under the terms of the GNU General Public License version 3, as published
383+ * by the Free Software Foundation.
384+ *
385+ * This program is distributed in the hope that it will be useful, but
386+ * WITHOUT ANY WARRANTY; without even the implied warranties of
387+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
388+ * PURPOSE. See the GNU General Public License for more details.
389+ *
390+ * You should have received a copy of the GNU General Public License along
391+ * with this program. If not, see <http://www.gnu.org/licenses/>.
392+ *
393+ */
394+
395+#include "inputprovider.h"
396
397=== added file 'src/mcs/inputprovider.h'
398--- src/mcs/inputprovider.h 1970-01-01 00:00:00 +0000
399+++ src/mcs/inputprovider.h 2015-12-18 16:38:21 +0000
400@@ -0,0 +1,46 @@
401+/*
402+ * Copyright (C) 2015 Canonical, Ltd.
403+ *
404+ * This program is free software: you can redistribute it and/or modify it
405+ * under the terms of the GNU General Public License version 3, as published
406+ * by the Free Software Foundation.
407+ *
408+ * This program is distributed in the hope that it will be useful, but
409+ * WITHOUT ANY WARRANTY; without even the implied warranties of
410+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
411+ * PURPOSE. See the GNU General Public License for more details.
412+ *
413+ * You should have received a copy of the GNU General Public License along
414+ * with this program. If not, see <http://www.gnu.org/licenses/>.
415+ *
416+ */
417+
418+#ifndef INPUTPROVIDER_H_
419+#define INPUTPROVIDER_H_
420+
421+#include <memory>
422+
423+#include "non_copyable.h"
424+#include "withdelegate.h"
425+
426+namespace mcs {
427+
428+class InputProviderDelegate : public mcs::NonCopyable {
429+public:
430+ virtual ~InputProviderDelegate() { }
431+ virtual void OnConnectedChanged() = 0;
432+};
433+
434+class InputProvider : public mcs::WithDelegate<InputProviderDelegate> {
435+public:
436+ typedef std::shared_ptr<InputProvider> Ptr;
437+
438+ virtual bool NewConnection(int fd) = 0;
439+ virtual void RequestDisconnection() = 0;
440+
441+ virtual bool Connected() const = 0;
442+};
443+
444+} // namespace mcs
445+
446+#endif
447
448=== added file 'src/mcs/inputproviderstub.cpp'
449--- src/mcs/inputproviderstub.cpp 1970-01-01 00:00:00 +0000
450+++ src/mcs/inputproviderstub.cpp 2015-12-18 16:38:21 +0000
451@@ -0,0 +1,137 @@
452+/*
453+ * Copyright (C) 2015 Canonical, Ltd.
454+ *
455+ * This program is free software: you can redistribute it and/or modify it
456+ * under the terms of the GNU General Public License version 3, as published
457+ * by the Free Software Foundation.
458+ *
459+ * This program is distributed in the hope that it will be useful, but
460+ * WITHOUT ANY WARRANTY; without even the implied warranties of
461+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
462+ * PURPOSE. See the GNU General Public License for more details.
463+ *
464+ * You should have received a copy of the GNU General Public License along
465+ * with this program. If not, see <http://www.gnu.org/licenses/>.
466+ *
467+ */
468+
469+#include <boost/concept_check.hpp>
470+
471+#include "inputproviderstub.h"
472+#include "keep_alive.h"
473+#include "logger.h"
474+
475+namespace mcs {
476+namespace dbus {
477+
478+std::shared_ptr<InputProviderStub> InputProviderStub::Create(const SharedGObject<GDBusConnection> &connection, const ObjectPath &path) {
479+ return std::shared_ptr<InputProviderStub>(new InputProviderStub(path))->FinalizeConstruction(connection);
480+}
481+
482+InputProviderStub::InputProviderStub(const ObjectPath &path) :
483+ path_(path),
484+ proxy_(nullptr),
485+ connected_(false) {
486+}
487+
488+InputProviderStub::~InputProviderStub() {
489+}
490+
491+void InputProviderStub::RequestDisconnection() {
492+ if (!connected_)
493+ return;
494+
495+ auto sp = shared_from_this();
496+
497+ aethercast_interface_input_provider_call_request_disconnection(proxy_,
498+ nullptr,
499+ InputProviderStub::OnNewConnectionFinish,
500+ new SharedKeepAlive<InputProviderStub>{sp});
501+}
502+
503+void InputProviderStub::OnRequestDisconnectionFinish(GObject *object, GAsyncResult *res, gpointer user_data) {
504+ boost::ignore_unused_variable_warning(object);
505+
506+ auto inst = static_cast<SharedKeepAlive<InputProviderStub>*>(user_data)->ShouldDie();
507+
508+ GError *error = nullptr;
509+ if (!aethercast_interface_input_provider_call_request_disconnection_finish(inst->proxy_, res, &error)) {
510+ ERROR("Failed to request disconnection of the input provider %s: %s", inst->path_, error->message);
511+ g_error_free(error);
512+ return;
513+ }
514+
515+ inst->connected_ = false;
516+
517+ if (auto sp = inst->delegate_.lock())
518+ sp->OnConnectedChanged();
519+}
520+
521+bool InputProviderStub::NewConnection(int fd) {
522+ if (connected_)
523+ return false;
524+
525+ auto sp = shared_from_this();
526+
527+ aethercast_interface_input_provider_call_new_connection(proxy_,
528+ g_variant_new_handle(fd),
529+ nullptr, // We don't have any options to provide yet
530+ nullptr,
531+ InputProviderStub::OnNewConnectionFinish,
532+ new SharedKeepAlive<InputProviderStub>{sp});
533+
534+ return true;
535+}
536+
537+void InputProviderStub::OnNewConnectionFinish(GObject *object, GAsyncResult *res, gpointer user_data) {
538+ boost::ignore_unused_variable_warning(object);
539+
540+ auto inst = static_cast<SharedKeepAlive<InputProviderStub>*>(user_data)->ShouldDie();
541+
542+ GError *error = nullptr;
543+ if (!aethercast_interface_input_provider_call_new_connection_finish(inst->proxy_, res, &error)) {
544+ ERROR("Failed to signal a new connection to the input provider %s: %s", inst->path_, error->message);
545+ g_error_free(error);
546+ return;
547+ }
548+
549+ inst->connected_ = true;
550+
551+ if (auto sp = inst->delegate_.lock())
552+ sp->OnConnectedChanged();
553+}
554+
555+void InputProviderStub::OnProxyConnected(GObject *object, GAsyncResult *res, gpointer user_data) {
556+ boost::ignore_unused_variable_warning(object);
557+
558+ auto inst = static_cast<SharedKeepAlive<InputProviderStub>*>(user_data)->ShouldDie();
559+
560+ GError *error = nullptr;
561+ inst->proxy_ = aethercast_interface_input_provider_proxy_new_finish(res, &error);
562+ if (!inst->proxy_) {
563+ ERROR("Failed to connect with input provider %s: %s", inst->path_, error->message);
564+ g_error_free(error);
565+ return;
566+ }
567+}
568+
569+std::shared_ptr<InputProviderStub> InputProviderStub::FinalizeConstruction(const SharedGObject<GDBusConnection> &connection) {
570+ auto sp = shared_from_this();
571+
572+ aethercast_interface_input_provider_proxy_new(connection.get(),
573+ G_DBUS_PROXY_FLAGS_NONE,
574+ nullptr,
575+ path_.c_str(),
576+ nullptr,
577+ &InputProviderStub::OnProxyConnected,
578+ new SharedKeepAlive<InputProviderStub>{sp});
579+
580+ return sp;
581+}
582+
583+bool InputProviderStub::Connected() const {
584+ return connected_;
585+}
586+
587+} // namespace dbus
588+} // namespace mcs
589
590=== added file 'src/mcs/inputproviderstub.h'
591--- src/mcs/inputproviderstub.h 1970-01-01 00:00:00 +0000
592+++ src/mcs/inputproviderstub.h 2015-12-18 16:38:21 +0000
593@@ -0,0 +1,67 @@
594+/*
595+ * Copyright (C) 2015 Canonical, Ltd.
596+ *
597+ * This program is free software: you can redistribute it and/or modify it
598+ * under the terms of the GNU General Public License version 3, as published
599+ * by the Free Software Foundation.
600+ *
601+ * This program is distributed in the hope that it will be useful, but
602+ * WITHOUT ANY WARRANTY; without even the implied warranties of
603+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
604+ * PURPOSE. See the GNU General Public License for more details.
605+ *
606+ * You should have received a copy of the GNU General Public License along
607+ * with this program. If not, see <http://www.gnu.org/licenses/>.
608+ *
609+ */
610+
611+#ifndef INPUTPROVIDERSTUB_H_
612+#define INPUTPROVIDERSTUB_H_
613+
614+#include <memory>
615+
616+#include "inputprovider.h"
617+
618+#include "dbus_types.h"
619+#include "shared_gobject.h"
620+
621+extern "C" {
622+#include "aethercastinterface.h"
623+}
624+
625+namespace mcs {
626+namespace dbus {
627+
628+class InputProviderStub : public std::enable_shared_from_this<InputProviderStub>,
629+ public InputProvider {
630+public:
631+ static constexpr const char *kManagerIface{"org.aethercast.InputProvider"};
632+
633+ static std::shared_ptr<InputProviderStub> Create(const SharedGObject<GDBusConnection> &connection, const ObjectPath &path);
634+
635+ ~InputProviderStub();
636+
637+ bool NewConnection(int fd);
638+ void RequestDisconnection();
639+
640+ bool Connected() const override;
641+
642+private:
643+ InputProviderStub(const ObjectPath &path);
644+ std::shared_ptr<InputProviderStub> FinalizeConstruction(const SharedGObject<GDBusConnection> &connection);
645+
646+private:
647+ static void OnProxyConnected(GObject *object, GAsyncResult *res, gpointer user_data);
648+ static void OnNewConnectionFinish(GObject *object, GAsyncResult *res, gpointer user_data);
649+ static void OnRequestDisconnectionFinish(GObject *object, GAsyncResult *res, gpointer user_data);
650+
651+private:
652+ std::string path_;
653+ AethercastInterfaceInputProvider *proxy_;
654+ bool connected_;
655+};
656+
657+} // namespace dbus
658+} // namespace mcs
659+
660+#endif
661
662=== modified file 'src/mcs/miracastcontroller.cpp'
663--- src/mcs/miracastcontroller.cpp 2015-12-11 21:10:24 +0000
664+++ src/mcs/miracastcontroller.cpp 2015-12-18 16:38:21 +0000
665@@ -0,0 +1,16 @@
666+/*
667+ * Copyright (C) 2015 Canonical, Ltd.
668+ *
669+ * This program is free software: you can redistribute it and/or modify it
670+ * under the terms of the GNU General Public License version 3, as published
671+ * by the Free Software Foundation.
672+ *
673+ * This program is distributed in the hope that it will be useful, but
674+ * WITHOUT ANY WARRANTY; without even the implied warranties of
675+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
676+ * PURPOSE. See the GNU General Public License for more details.
677+ *
678+ * You should have received a copy of the GNU General Public License along
679+ * with this program. If not, see <http://www.gnu.org/licenses/>.
680+ *
681+ */
682
683=== modified file 'src/mcs/miracastcontroller.h'
684--- src/mcs/miracastcontroller.h 2015-12-11 21:10:24 +0000
685+++ src/mcs/miracastcontroller.h 2015-12-18 16:38:21 +0000
686@@ -22,6 +22,7 @@
687 #include <memory>
688
689 #include "networkdevice.h"
690+#include "inputprovider.h"
691 #include "non_copyable.h"
692 #include "types.h"
693
694@@ -57,6 +58,10 @@
695 virtual std::vector<NetworkDeviceRole> SupportedRoles() const = 0;
696 virtual bool Scanning() const = 0;
697
698+ virtual bool HasInputProvider() const = 0;
699+ virtual void SetInputProvider(const InputProvider::Ptr &provider) = 0;
700+ virtual void ResetInputProvider() = 0;
701+
702 protected:
703
704 };
705
706=== modified file 'src/mcs/miracastcontrollerskeleton.cpp'
707--- src/mcs/miracastcontrollerskeleton.cpp 2015-12-16 14:59:45 +0000
708+++ src/mcs/miracastcontrollerskeleton.cpp 2015-12-18 16:38:21 +0000
709@@ -23,6 +23,8 @@
710 #include <boost/concept_check.hpp>
711
712 #include "miracastcontrollerskeleton.h"
713+#include "inputproviderstub.h"
714+
715 #include "keep_alive.h"
716 #include "utils.h"
717 #include "dbushelpers.h"
718@@ -114,13 +116,18 @@
719 SyncProperties();
720 }
721
722+#define CONNECT_HANDLER(signal, callback) \
723+ g_signal_connect_data(inst->manager_obj_.get(), signal, \
724+ G_CALLBACK(&MiracastControllerSkeleton::callback), new WeakKeepAlive<MiracastControllerSkeleton>(inst), \
725+ [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0))
726+
727 void MiracastControllerSkeleton::OnNameAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) {
728 auto inst = static_cast<SharedKeepAlive<MiracastControllerSkeleton>*>(user_data)->ShouldDie();
729 inst->manager_obj_.reset(aethercast_interface_manager_skeleton_new());
730
731- g_signal_connect_data(inst->manager_obj_.get(), "handle-scan",
732- G_CALLBACK(&MiracastControllerSkeleton::OnHandleScan), new WeakKeepAlive<MiracastControllerSkeleton>(inst),
733- [](gpointer data, GClosure *) { delete static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(data); }, GConnectFlags(0));
734+ CONNECT_HANDLER("handle-scan", OnHandleScan);
735+ CONNECT_HANDLER("handle-register-input-provider", OnHandleRegisterInputProvider);
736+ CONNECT_HANDLER("handle-unregister-input-provider", OnHandleUnregisterInputProvider);
737
738 inst->SyncProperties();
739
740@@ -152,6 +159,62 @@
741 return TRUE;
742 }
743
744+gboolean MiracastControllerSkeleton::OnHandleRegisterInputProvider(AethercastInterfaceManager *skeleton,
745+ GDBusMethodInvocation *invocation,
746+ const char *path, GVariant *options,
747+ gpointer user_data) {
748+ boost::ignore_unused_variable_warning(skeleton);
749+ auto inst = static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(user_data)->GetInstance().lock();
750+
751+ if (not inst) {
752+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
753+ return TRUE;
754+ }
755+
756+ DEBUG("Got request for new input provider %s", path);
757+
758+ if (inst->HasInputProvider()) {
759+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
760+ "Input provider is already registered");
761+ return TRUE;
762+ }
763+
764+ auto provider = mcs::dbus::InputProviderStub::Create(inst->bus_connection_, mcs::dbus::ObjectPath(path));
765+
766+ inst->SetInputProvider(provider);
767+
768+ g_dbus_method_invocation_return_value(invocation, nullptr);
769+
770+ return TRUE;
771+}
772+
773+gboolean MiracastControllerSkeleton::OnHandleUnregisterInputProvider(AethercastInterfaceManager *skeleton,
774+ GDBusMethodInvocation *invocation,
775+ const char *path,
776+ gpointer user_data) {
777+ boost::ignore_unused_variable_warning(skeleton);
778+ auto inst = static_cast<WeakKeepAlive<MiracastControllerSkeleton>*>(user_data)->GetInstance().lock();
779+
780+ if (not inst) {
781+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
782+ return TRUE;
783+ }
784+
785+ DEBUG("Got request to remove input provider %s", path);
786+
787+ if (!inst->HasInputProvider()) {
788+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
789+ "Input provider is not registered");
790+ return TRUE;
791+ }
792+
793+ inst->ResetInputProvider();
794+
795+ g_dbus_method_invocation_return_value(invocation, nullptr);
796+
797+ return TRUE;
798+}
799+
800 std::shared_ptr<MiracastControllerSkeleton> MiracastControllerSkeleton::FinalizeConstruction() {
801 auto sp = shared_from_this();
802
803
804=== modified file 'src/mcs/miracastcontrollerskeleton.h'
805--- src/mcs/miracastcontrollerskeleton.h 2015-12-16 14:59:45 +0000
806+++ src/mcs/miracastcontrollerskeleton.h 2015-12-18 16:38:21 +0000
807@@ -18,13 +18,9 @@
808 #ifndef MIRACASTSERVICEADAPTOR_H_
809 #define MIRACASTSERVICEADAPTOR_H_
810
811-#ifdef __cplusplus
812 extern "C" {
813-#endif
814 #include "aethercastinterface.h"
815-#ifdef __cplusplus
816 }
817-#endif
818
819 #include <memory>
820 #include <unordered_map>
821@@ -59,6 +55,14 @@
822 static gboolean OnHandleScan(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
823 gpointer user_data);
824
825+ static gboolean OnHandleRegisterInputProvider(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
826+ const char *path, GVariant *options,
827+ gpointer user_data);
828+
829+ static gboolean OnHandleUnregisterInputProvider(AethercastInterfaceManager *skeleton, GDBusMethodInvocation *invocation,
830+ const char *path,
831+ gpointer user_data);
832+
833 MiracastControllerSkeleton(const std::shared_ptr<MiracastController> &controller);
834 std::shared_ptr<MiracastControllerSkeleton> FinalizeConstruction();
835
836
837=== modified file 'src/mcs/miracastservice.cpp'
838--- src/mcs/miracastservice.cpp 2015-12-16 14:59:45 +0000
839+++ src/mcs/miracastservice.cpp 2015-12-18 16:38:21 +0000
840@@ -346,4 +346,20 @@
841 void MiracastService::Scan(const std::chrono::seconds &timeout) {
842 network_manager_->Scan(timeout);
843 }
844+
845+bool MiracastService::HasInputProvider() const {
846+ return !!input_provider_;
847+}
848+
849+void MiracastService::SetInputProvider(const InputProvider::Ptr &provider) {
850+ input_provider_ = provider;
851+}
852+
853+void MiracastService::ResetInputProvider() {
854+ if (input_provider_->Connected())
855+ input_provider_->RequestDisconnection();
856+
857+ input_provider_.reset();
858+}
859+
860 } // namespace miracast
861
862=== modified file 'src/mcs/miracastservice.h'
863--- src/mcs/miracastservice.h 2015-12-11 21:10:24 +0000
864+++ src/mcs/miracastservice.h 2015-12-18 16:38:21 +0000
865@@ -30,6 +30,8 @@
866 #include "miracastsourcemanager.h"
867 #include "networkmanager.h"
868 #include "networkdevice.h"
869+#include "inputprovider.h"
870+
871 #include "non_copyable.h"
872 #include "types.h"
873
874@@ -70,6 +72,10 @@
875 std::vector<NetworkDeviceRole> SupportedRoles() const;
876 bool Scanning() const;
877
878+ bool HasInputProvider() const;
879+ void SetInputProvider(const InputProvider::Ptr &provider);
880+ void ResetInputProvider();
881+
882 void OnClientDisconnected();
883
884 public:
885@@ -101,6 +107,7 @@
886 guint scan_timeout_source_;
887 ResultCallback current_scan_callback_;
888 std::vector<NetworkDeviceRole> supported_roles_;
889+ InputProvider::Ptr input_provider_;
890 };
891 } // namespace mcs
892 #endif
893
894=== added file 'src/mcs/withdelegate.cpp'
895--- src/mcs/withdelegate.cpp 1970-01-01 00:00:00 +0000
896+++ src/mcs/withdelegate.cpp 2015-12-18 16:38:21 +0000
897@@ -0,0 +1,16 @@
898+/*
899+ * Copyright (C) 2015 Canonical, Ltd.
900+ *
901+ * This program is free software: you can redistribute it and/or modify it
902+ * under the terms of the GNU General Public License version 3, as published
903+ * by the Free Software Foundation.
904+ *
905+ * This program is distributed in the hope that it will be useful, but
906+ * WITHOUT ANY WARRANTY; without even the implied warranties of
907+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
908+ * PURPOSE. See the GNU General Public License for more details.
909+ *
910+ * You should have received a copy of the GNU General Public License along
911+ * with this program. If not, see <http://www.gnu.org/licenses/>.
912+ *
913+ */
914
915=== added file 'src/mcs/withdelegate.h'
916--- src/mcs/withdelegate.h 1970-01-01 00:00:00 +0000
917+++ src/mcs/withdelegate.h 2015-12-18 16:38:21 +0000
918@@ -0,0 +1,37 @@
919+/*
920+ * Copyright (C) 2015 Canonical, Ltd.
921+ *
922+ * This program is free software: you can redistribute it and/or modify it
923+ * under the terms of the GNU General Public License version 3, as published
924+ * by the Free Software Foundation.
925+ *
926+ * This program is distributed in the hope that it will be useful, but
927+ * WITHOUT ANY WARRANTY; without even the implied warranties of
928+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
929+ * PURPOSE. See the GNU General Public License for more details.
930+ *
931+ * You should have received a copy of the GNU General Public License along
932+ * with this program. If not, see <http://www.gnu.org/licenses/>.
933+ *
934+ */
935+
936+#ifndef WITHDELEGATE_H_
937+#define WITHDELEGATE_H_
938+
939+#include <memory>
940+
941+namespace mcs {
942+
943+template <typename T>
944+class WithDelegate {
945+public:
946+ void SetDelegate(const std::weak_ptr<T> &delegate) { delegate_ = delegate; }
947+ void ResetDelegate() { delegate_.reset(); }
948+
949+protected:
950+ std::weak_ptr<T> delegate_;
951+};
952+
953+} // namespace mcs
954+
955+#endif
956
957=== modified file 'tests/mcs/CMakeLists.txt'
958--- tests/mcs/CMakeLists.txt 2015-12-11 22:02:52 +0000
959+++ tests/mcs/CMakeLists.txt 2015-12-18 16:38:21 +0000
960@@ -24,4 +24,12 @@
961 target_link_libraries(miracastcontrollerskeleton_tests aethercast-core gmock gmock_main)
962 add_test(miracastcontrollerskeleton_tests miracastcontrollerskeleton_tests)
963
964+add_executable(inputeventchannel_tests inputeventchannel_tests.cpp)
965+target_link_libraries(inputeventchannel_tests aethercast-core gmock gmock_main)
966+add_test(inputeventchannel_tests inputeventchannel_tests)
967+
968+add_executable(miracastservice_tests miracastservice_tests.cpp)
969+target_link_libraries(miracastservice_tests aethercast-core gmock gmock_main)
970+add_test(miracastservice_tests miracastservice_tests)
971+
972 add_subdirectory(acceptance_tests)
973
974=== modified file 'tests/mcs/forwardingmiracastcontroller_tests.cpp'
975--- tests/mcs/forwardingmiracastcontroller_tests.cpp 2015-12-11 22:02:52 +0000
976+++ tests/mcs/forwardingmiracastcontroller_tests.cpp 2015-12-18 16:38:21 +0000
977@@ -32,6 +32,10 @@
978 MOCK_CONST_METHOD0(State, mcs::NetworkDeviceState());
979 MOCK_CONST_METHOD0(SupportedRoles, std::vector<mcs::NetworkDeviceRole>());
980 MOCK_CONST_METHOD0(Scanning, bool());
981+
982+ MOCK_CONST_METHOD0(HasInputProvider, bool());
983+ MOCK_METHOD1(SetInputProvider, void(const mcs::InputProvider::Ptr &));
984+ MOCK_METHOD0(ResetInputProvider, void());
985 };
986 }
987
988@@ -52,6 +56,9 @@
989 EXPECT_CALL(*impl, State()).Times(1).WillRepeatedly(Return(mcs::NetworkDeviceState::kConnected));
990 EXPECT_CALL(*impl, SupportedRoles()).Times(1).WillRepeatedly(Return(std::vector<mcs::NetworkDeviceRole>{mcs::NetworkDeviceRole::kSource}));
991 EXPECT_CALL(*impl, Scanning()).Times(1).WillRepeatedly(Return(true));
992+ EXPECT_CALL(*impl, HasInputProvider()).Times(1);
993+ EXPECT_CALL(*impl, SetInputProvider(_)).Times(1);
994+ EXPECT_CALL(*impl, ResetInputProvider()).Times(1);
995
996 mcs::ForwardingMiracastController fmc{impl};
997 fmc.SetDelegate(std::shared_ptr<mcs::MiracastController::Delegate>{});
998@@ -62,4 +69,7 @@
999 fmc.State();
1000 fmc.SupportedRoles();
1001 fmc.Scanning();
1002+ fmc.HasInputProvider();
1003+ fmc.SetInputProvider(nullptr);
1004+ fmc.ResetInputProvider();
1005 }
1006
1007=== added file 'tests/mcs/inputeventchannel_tests.cpp'
1008--- tests/mcs/inputeventchannel_tests.cpp 1970-01-01 00:00:00 +0000
1009+++ tests/mcs/inputeventchannel_tests.cpp 2015-12-18 16:38:21 +0000
1010@@ -0,0 +1,66 @@
1011+/*
1012+ * Copyright (C) 2015 Canonical, Ltd.
1013+ *
1014+ * This program is free software: you can redistribute it and/or modify it
1015+ * under the terms of the GNU General Public License version 3, as published
1016+ * by the Free Software Foundation.
1017+ *
1018+ * This program is distributed in the hope that it will be useful, but
1019+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1020+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1021+ * PURPOSE. See the GNU General Public License for more details.
1022+ *
1023+ * You should have received a copy of the GNU General Public License along
1024+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1025+ *
1026+ */
1027+
1028+#include <gmock/gmock.h>
1029+
1030+#include <mcs/inputeventchannel.h>
1031+
1032+#include <linux/input.h>
1033+
1034+namespace {
1035+class MockInputEventChannelDelegate : public mcs::InputEventChannelDelegate {
1036+public:
1037+ MOCK_METHOD0(OnChannelClosed, void());
1038+ MOCK_METHOD1(OnEvent, void(const mcs::InputEvent &));
1039+};
1040+
1041+static void RunMainLoopIteration() {
1042+ std::shared_ptr<GMainLoop> loop(g_main_loop_new(nullptr, false), &g_main_loop_unref);
1043+ auto context = g_main_loop_get_context(loop.get());
1044+ g_main_context_iteration(context, TRUE);
1045+}
1046+}
1047+
1048+TEST(InputEventChannel, ChannelGotClosed) {
1049+ auto delegate = std::make_shared<MockInputEventChannelDelegate>();
1050+
1051+ EXPECT_CALL(*delegate, OnChannelClosed()).Times(1);
1052+
1053+ auto channel = mcs::InputEventChannel::Create();
1054+ channel->SetDelegate(delegate);
1055+
1056+ ::close(channel->RemoteEndpoint());
1057+
1058+ RunMainLoopIteration();
1059+}
1060+
1061+TEST(InputEventChannel, EventReporting) {
1062+ using namespace ::testing;
1063+
1064+ auto delegate = std::make_shared<MockInputEventChannelDelegate>();
1065+
1066+ EXPECT_CALL(*delegate, OnEvent(_)).Times(1);
1067+
1068+ auto channel = mcs::InputEventChannel::Create();
1069+ channel->SetDelegate(delegate);
1070+
1071+ struct input_event ev = {{0, 0}, EV_ABS, ABS_X, 42};
1072+ EXPECT_EQ(::write(channel->RemoteEndpoint(), &ev, sizeof(ev)), sizeof(ev));
1073+
1074+ RunMainLoopIteration();
1075+}
1076+
1077
1078=== modified file 'tests/mcs/miracastcontrollerskeleton_tests.cpp'
1079--- tests/mcs/miracastcontrollerskeleton_tests.cpp 2015-12-12 20:03:23 +0000
1080+++ tests/mcs/miracastcontrollerskeleton_tests.cpp 2015-12-18 16:38:21 +0000
1081@@ -32,6 +32,10 @@
1082 MOCK_CONST_METHOD0(State, mcs::NetworkDeviceState());
1083 MOCK_CONST_METHOD0(SupportedRoles, std::vector<mcs::NetworkDeviceRole>());
1084 MOCK_CONST_METHOD0(Scanning, bool());
1085+
1086+ MOCK_CONST_METHOD0(HasInputProvider, bool());
1087+ MOCK_METHOD1(SetInputProvider, void(const mcs::InputProvider::Ptr &));
1088+ MOCK_METHOD0(ResetInputProvider, void());
1089 };
1090 }
1091
1092
1093=== added file 'tests/mcs/miracastservice_tests.cpp'
1094--- tests/mcs/miracastservice_tests.cpp 1970-01-01 00:00:00 +0000
1095+++ tests/mcs/miracastservice_tests.cpp 2015-12-18 16:38:21 +0000
1096@@ -0,0 +1,78 @@
1097+/*
1098+ * Copyright (C) 2015 Canonical, Ltd.
1099+ *
1100+ * This program is free software: you can redistribute it and/or modify it
1101+ * under the terms of the GNU General Public License version 3, as published
1102+ * by the Free Software Foundation.
1103+ *
1104+ * This program is distributed in the hope that it will be useful, but
1105+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1106+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1107+ * PURPOSE. See the GNU General Public License for more details.
1108+ *
1109+ * You should have received a copy of the GNU General Public License along
1110+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1111+ *
1112+ */
1113+
1114+#include <gmock/gmock.h>
1115+
1116+#include <mcs/miracastservice.h>
1117+
1118+class MockNetworkManager : public mcs::NetworkManager {
1119+public:
1120+ MOCK_METHOD1(SetDelegate, void(mcs::NetworkManager::Delegate*));
1121+ MOCK_METHOD0(Setup, bool());
1122+ MOCK_METHOD1(Scan, void(const std::chrono::seconds &));
1123+ MOCK_METHOD1(Connect, bool(const mcs::NetworkDevice::Ptr &));
1124+ MOCK_METHOD1(Disconnect, bool(const mcs::NetworkDevice::Ptr &));
1125+ MOCK_METHOD1(SetWfdSubElements, void(const std::list<std::string> &));
1126+
1127+ MOCK_CONST_METHOD0(Devices, std::vector<mcs::NetworkDevice::Ptr>());
1128+ MOCK_CONST_METHOD0(LocalAddress, mcs::IpV4Address());
1129+ MOCK_CONST_METHOD0(Running, bool());
1130+ MOCK_CONST_METHOD0(Scanning, bool());
1131+};
1132+
1133+class MockInputProvider : public mcs::InputProvider {
1134+public:
1135+ MOCK_METHOD1(NewConnection, bool(int));
1136+ MOCK_METHOD0(RequestDisconnection, void());
1137+ MOCK_CONST_METHOD0(Connected, bool());
1138+};
1139+
1140+TEST(MiracastService, CorrectConstruction) {
1141+ using namespace ::testing;
1142+
1143+ auto network_manager = std::make_shared<MockNetworkManager>();
1144+
1145+ EXPECT_CALL(*network_manager, SetDelegate(_)).Times(1);
1146+ EXPECT_CALL(*network_manager, Setup()).Times(1);
1147+
1148+ auto service = mcs::MiracastService::Create(network_manager);
1149+ EXPECT_TRUE(!!service);
1150+}
1151+
1152+TEST(MiracastService, InputProviderRegistration) {
1153+ using namespace ::testing;
1154+
1155+ auto network_manager = std::make_shared<MockNetworkManager>();
1156+
1157+ EXPECT_CALL(*network_manager, SetDelegate(_)).Times(1);
1158+ EXPECT_CALL(*network_manager, Setup()).Times(1);
1159+
1160+ auto service = mcs::MiracastService::Create(network_manager);
1161+ EXPECT_TRUE(!!service);
1162+
1163+ auto input_provider = std::make_shared<MockInputProvider>();
1164+
1165+ EXPECT_FALSE(service->HasInputProvider());
1166+
1167+ service->SetInputProvider(input_provider);
1168+
1169+ EXPECT_TRUE(service->HasInputProvider());
1170+
1171+ service->ResetInputProvider();
1172+
1173+ EXPECT_FALSE(service->HasInputProvider());
1174+}

Subscribers

People subscribed via source and target branches

to all changes: