%define tizen_feature_tvinputdevice_support 0
+%if 0%{?tizen_is_emulator}
+%define tizen_feature_convergence_support 0
+%else
+%define tizen_feature_convergence_support 1
+%endif
+
%endif # tizen_profile_mobile
####################################################################
%define tizen_feature_nbs_support 0
%endif
+%if 0%{?tizen_is_emulator}
+%define tizen_feature_convergence_support 0
+%else
+%define tizen_feature_convergence_support 1
+%endif
+
%endif # tizen_profile_wearable
####################################################################
%define tizen_feature_wi_fi_support 1
%define tizen_feature_inputdevice_support 0
%define tizen_feature_tvinputdevice_support 1
+%define tizen_feature_convergence_support 1
%endif # tizen_profile_tv
BuildRequires: pkgconfig(capi-system-media-key)
%endif
+%if 0%{?tizen_feature_convergence_support}
+BuildRequires: pkgconfig(d2d-conv-manager)
+%endif
+
%if 0%{?tizen_feature_widget_service_support}
BuildRequires: pkgconfig(widget_service)
%endif
GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_feature_widget_service_support}"
GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_feature_wi_fi_support}"
GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_convergence_support=%{?tizen_feature_convergence_support}"
./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
--- /dev/null
+{
+ 'includes':[
+ '../common/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'tizen_convergence',
+ 'type': 'loadable_module',
+ 'dependencies': [
+ '../common/common.gyp:tizen_common',
+ ],
+ 'sources': [
+ 'convergence_api.js',
+ 'convergence_extension.cc',
+ 'convergence_extension.h',
+ 'convergence_instance.cc',
+ 'convergence_instance.h',
+ 'convergence_utils.cc',
+ 'convergence_utils.h',
+ 'convergence_manager.cc',
+ 'convergence_manager.h',
+ 'convergence_device.cc',
+ 'convergence_device.h',
+ 'convergence_service.cc',
+ 'convergence_service.h',
+ 'convergence_remote_app_control_service.cc',
+ 'convergence_remote_app_control_service.h',
+ 'convergence_app_communication_service.cc',
+ 'convergence_app_communication_service.h',
+ 'convergence_channel.cc',
+ 'convergence_channel.h',
+ 'convergence_payload.cc',
+ 'convergence_payload.h',
+ 'convergence_client_info.cc',
+ 'convergence_client_info.h',
+ ],
+ 'conditions': [
+ ['tizen == 1', {
+ 'variables': {
+ 'packages': [
+ 'd2d-conv-manager',
+ ]
+ },
+ }],
+ ],
+ },
+ ],
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+var validator_ = xwalk.utils.validator;
+var types_ = validator_.Types;
+var utils_ = xwalk.utils;
+var native_ = new utils_.NativeManager(extension);
+var T_ = utils_.type;
+
+// Flag showing if the discovery procedure has started
+var discoveryStarted = false;
+
+// Currently available devices
+var convergenceDevices = [];
+
+// Issued service objects
+// We should stor it for proper calling user callbacks
+var nextServiceId = 0; // Next service id (internally used on JS layer)
+var convergenceServices = {}; // Issued services
+
+var ConnectionState = {
+ CONNECTED: 'CONNECTED',
+ NOT_CONNECTED: 'NOT_CONNECTED',
+ CONNECTING: 'CONNECTING'
+};
+
+var DeviceProfile = {
+ MOBILE: 'MOBILE',
+ WEARABLE: 'WEARABLE',
+ TV: 'TV'
+};
+
+
+var PayloadType = {
+ STRING: 'STRING',
+ RAW_BYTES: 'RAW_BYTES'
+};
+
+function SetReadOnlyProperty(obj, n, v) {
+ if (arguments.length > 2)
+ Object.defineProperty(
+ obj, n, {
+ value: v,
+ writable: false,
+ enumerable: true,
+ configurable: true
+ });
+ else
+ Object.defineProperty(obj, n, {
+ writable: false,
+ enumerable: true,
+ configurable: true
+ });
+}
+
+
+function getServiceConnectionStateName(connectionStateNumber) {
+ switch(connectionStateNumber) {
+ case 0:
+ return ConnectionState.CONNECTED;
+ case 1:
+ return ConnectionState.NOT_CONNECTED;
+ case 2:
+ return ConnectionState.CONNECTING;
+ default:
+ console.log('ERROR: Unknown connection state');
+ return -1; // TODO throw exception
+ }
+}
+
+function Device(id, name, profile, services) {
+ validator_.isConstructorCall(this, Device);
+ this.id = id;
+ this.name = name;
+ this.profile = profile;
+ this.services = services;
+}
+
+function ConvergenceManager() {
+ // constructor of ConvergenceManager
+}
+
+ConvergenceManager.prototype.startDiscovery = function(successCallback,
+ errorCallback, timeout) {
+ console.log('Entered ConvergenceManager.startDiscovery()');
+ var args = validator_.validateArgs(arguments, [
+ {name: 'successCallback', type: types_.LISTENER, values: ['onfound', 'onfinished' ]},
+ {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true},
+ {name: 'timeout', type: types_.LONG, optional: true, nullable: true}
+ ]);
+
+ // Indicate, that discovery procedure is on
+ discoveryStarted = true;
+
+ // Reset currently available device list
+ convergenceDevices = [];
+
+ native_.addListener('CONVERGENCE_DISCOVERY_LISTENER', function(result) {
+ console.log('Entered discovery listener');
+
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ } else {
+ if (result.discovery_status == 'device_found') {
+
+ // Prepare service array
+ if (!result || !result.device || !result.device.services) {
+ console.log('INVALID device info obtained from Native API'); // TODO throw exception
+ return;
+ }
+
+ // Create an instance of the device
+ var d = new Device(result.device.id, result.device.name, result.device.type, []);
+
+ console.log('Service number: ' + result.device.services.length);
+ for (var i = 0; i < result.device.services.length; ++i) {
+ var service_data = result.device.services[i];
+ var s;
+ if (service_data.serviceType == 0) { // App Communication Client
+ s = new AppCommunicationClientService();
+ } else if (service_data.serviceType == 1) { // Remote App Control
+ s = new RemoteAppControlService();
+ } else {
+ // Error: unknown service type
+ // TODO throw exception
+ console.log('UNKNOWN SERVICE TYPE: ' + service_data.serviceType);
+ continue;
+ }
+
+ s.connectionState = getServiceConnectionStateName(
+ result.device.services[i].connectionState);
+ s._deviceId = d.id;
+ d.services.push(s);
+ }
+
+ // Store newly found device internally
+ convergenceDevices.push(d);
+
+ // Invoke user callback retrieving newly found device
+ native_.callIfPossible(successCallback.onfound, d);
+
+ } else if (result.discovery_status == 'discovery_finished') {
+ // Unregister discovery listener, because Convergence Manager is a
+ // singleton object and no one else can receive discovery results
+ native_.removeListener('CONVERGENCE_DISCOVERY_LISTENER');
+
+ // Notify the customer about discovery results
+ native_.callIfPossible(successCallback.onfinished, convergenceDevices.slice());
+ convergenceDevices = [];
+
+ } else {
+ console.log('UNKNOWN discovery state exception'); // TODO throw exception
+ }
+ }
+ });
+
+ // Start the discovery using Native API
+ var result = native_.call('ConvergenceManager_startDiscovery', {
+ timeout: (args.timeout) ? args.timeout : 0
+ }, function(result) {
+ if (native_.isFailure(result)) {
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ }
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+ConvergenceManager.prototype.stopDiscovery = function() {
+ console.log('Entered ConvergenceManager.stopDiscovery()');
+
+ if (!discoveryStarted)
+ throw new WebAPIException('InvalidStateError', 'Discovery has not started yet.');
+
+ discoveryStarted = false;
+
+ var result = native_.callSync('ConvergenceManager_stopDiscovery', null);
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+function Service() {
+ console.log('Entered Service.constructor()');
+
+ //validator_.isConstructorCall(this, Service);
+ this.connectionState = ConnectionState.NOT_CONNECTED;
+}
+
+native_.addListener('REMOTE_APP_CONTROL_SERVICE_LISTENER', function(result) {
+ if (native_.isFailure(result)) {
+ //native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ console.log('Error in REMOTE_APP_CONTROL_SERVICE_LISTENER');
+ } else {
+
+ console.log('');
+ console.log('REMOTE_APP_CONTROL_SERVICE_LISTENER invoked with data');
+ console.log(JSON.stringify(result));
+ console.log('');
+
+ // Invoke corresponding callback
+ var lid = result.curListenerId;
+ if (!lid || !convergenceServices.hasOwnProperty(lid)) {
+ console.log('ERROR: Remote App Ctrl listener is not registered [' + lid + ']');
+ return; // Something is wrong: listener MUST be there
+ }
+ var s = convergenceServices[lid];
+
+ var result_type = result.result_type;
+
+ switch (result_type) {
+ case 'Connected':
+ if (s) { // Service MUST NOT be null here
+ s.connectionState = ConnectionState.CONNECTED;
+ convergenceServices[lid] = s;
+ }
+ native_.callIfPossible(s._connectCallback, s);
+ break;
+ case 'onPublish':
+ native_.callIfPossible(s._remoteAppControlCallback,
+ result.payload);
+ break;
+ default:
+ console.log('Ignoring result type: [' + result_type + ']');
+ break;
+ }
+ }
+});
+
+function RemoteAppControlService() {
+ console.log('Entered RemoteAppControlService.constructor()');
+
+ validator_.isConstructorCall(this, RemoteAppControlService);
+
+ // The device id is needed for getting the valid service handle on the
+ // native layer
+ // I have to implement this property here instead of base constructor in order
+ // to mask it from accessing
+ Object.defineProperties(this, {
+ _serviceId : {
+ value: ++nextServiceId,
+ writable: false,
+ enumerable: false
+ },
+ // The id of device of the service or 'localhost' for local service
+ _deviceId : {
+ value: 'localhost',
+ writable: true,
+ enumerable: false
+ },
+ // Remote App Control Service user-defined callbacks
+ _connectCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ },
+ _remoteAppControlCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ }
+ });
+
+ // Registering the service in the table of issued services
+ convergenceServices[this._serviceId] = this;
+}
+
+RemoteAppControlService.prototype = new Service();
+
+RemoteAppControlService.prototype.connect = function(successCallback, errorCallback) {
+ console.log('Entered RemoteAppControlService.connect()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ if (this.serviceState == ConnectionState.CONNECTED)
+ throw new WebAPIException('InvalidStateError', 'Service is connected already.');
+
+ var lid = this._serviceId;
+ this._connectCallback = successCallback;
+ convergenceServices[lid] = this;
+
+ var result = native_.call('RemoteAppControlService_connect', {
+ deviceId: this._deviceId,
+ curListenerId: lid
+ }, function(result) {
+ if (native_.isFailure(result))
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+RemoteAppControlService.prototype.disconnect = function(successCallback, errorCallback) {
+ console.log('Entered RemoteAppControlService.disconnect()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ if (this.serviceState != ConnectionState.CONNECTED) {
+ throw new WebAPIException('InvalidStateError', 'Service is not connected yet.');
+ }
+
+ var result = native_.callSync('RemoteAppControlService_disconnect', {
+ deviceId: this._deviceId
+ });
+
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+ else
+ connectionState = ConnectionState.DISCONNECTED;
+
+ native_.callIfPossible(successCallback, this);
+};
+
+RemoteAppControlService.prototype.launch = function(appId, successCallback, errorCallback) {
+ console.log('Entered RemoteAppControlService.launch()');
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'appId',
+ //type: types_.PLATFORM_OBJECT,
+ type: types_.STRING,
+ values: tizen.ApplicationId,
+ optional: false,
+ nullable:false
+ },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: RemoteAppControlCallback,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ if (this.serviceState == ConnectionState.CONNECTED)
+ throw new WebAPIException('InvalidStateError', 'Service is connected already.');
+
+ var lid = this._serviceId;
+ // TODO In fact it must be a list of callbacks
+ // But untill D2D FW suppurts transaction management, it is meaningless to
+ // have more than one callback, because all payload is delivered to
+ // a single point without identification of initial request
+ this._remoteAppControlCallback = successCallback;
+ convergenceServices[lid] = this;
+
+ var needReply = !(successCallback == null);
+
+ var result = native_.call('RemoteAppControlService_launch', {
+ appId: args.appId,
+ reply: needReply,
+ deviceId: this._deviceId,
+ curListenerId: lid
+ }, function(result) {
+ if (native_.isFailure(result))
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+RemoteAppControlService.prototype.launchAppControl = function(
+ appControl, appId, successCallback, errorCallback) {
+ console.log('Entered RemoteAppControlService.launchAppControl()');
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'appControl',
+ type: types_.PLATFORM_OBJECT,
+ values: tizen.ApplicationControl,
+ optional: false,
+ nullable:false
+ },
+ {
+ name: 'appId',
+ type: types_.PLATFORM_OBJECT,
+ values: tizen.ApplicationId,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: RemoteAppControlCallback,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ // TODO Implement pls
+
+ return; // TODO remove when native layer is implemented
+};
+
+function AppCommunicationService() {
+ console.log('Entered AppCommunicationService.constructor()');
+
+ // The device id is needed for getting the valid service handle on the
+ // native layer
+ // I have to implement this property here instead of base constructor in order
+ // to mask it from accessing
+ Object.defineProperties(this, {
+ _serviceId : {
+ value: ++nextServiceId,
+ writable: false,
+ enumerable: false
+ },
+ // The id of device of the service or 'localhost' for local service
+ _deviceId : {
+ value: 'localhost',
+ writable: true,
+ enumerable: false
+ },
+ // App Communication Service basic callbacks
+ _connectCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ },
+ _startCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ },
+ _sendCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ },
+ _stopCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ },
+ _listenerCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ },
+ _getClientListCallback : {
+ value: null,
+ writable: true,
+ enumerable: false
+ }
+ });
+
+ // TODO add callbacks in runtime instead of constructor
+
+ // Registering the service in the table of issued services
+ convergenceServices[this._serviceId] = this;
+}
+
+AppCommunicationService.prototype = new Service();
+
+native_.addListener('APP_COMMUNICATION_SERVICE_LISTENER', function(result) {
+
+ console.log('On App Communication Service Success Callback');
+
+ if (native_.isFailure(result)) {
+ console.log('ERROR in APP_COMMUNICATION_SERVICE_LISTENER');
+ //native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ } else {
+
+ console.log('');
+ console.log('APP_COMMUNICATION_SERVICE_LISTENER invoked with data');
+ console.log(JSON.stringify(result));
+ console.log('');
+
+ // Invoke corresponding callback
+ var lid = result.curListenerId;
+ if (!lid || !convergenceServices.hasOwnProperty(lid)) {
+ console.log('ERROR: App Comm listener is not registered [' + lid + ']');
+ return; // Something is wrong: listener MUST be there
+ }
+ var s = convergenceServices[lid];
+
+ var result_type = result.result_type;
+
+ switch (result_type) {
+ case 'Connected':
+ if (s) { // Service MUST NOT be null here
+ s.connectionState = ConnectionState.CONNECTED;
+ convergenceServices[lid] = s;
+ }
+ native_.callIfPossible(s._connectCallback, s);
+ break;
+ case 'onStart':
+ native_.callIfPossible(s._startCallback,
+ new Channel(result.channel.uri, result.channel.id), null);
+ break;
+ case 'onPublish':
+ native_.callIfPossible(s._sendCallback,
+ new Channel(result.channel.uri, result.channel.id), null);
+ break;
+ case 'onStop':
+ native_.callIfPossible(s._stopCallback,
+ new Channel(result.channel.uri, result.channel.id), null);
+ break;
+ case 'onMessage': {
+ var payload = [];
+ for(var i = 0; i < result.payload.length; i++) {
+ var curPl = result.payload[i];
+ switch(curPl.type) {
+ case PayloadType.STRING:
+ payload.push(new PayloadString(curPl.key, curPl.value));
+ break;
+ case PayloadType.RAW_BYTES:
+ payload.push(new PayloadRawBytes(curPl.key, curPl.value));
+ break;
+ default:
+ console.log('ERROR: Unknown payload type');
+ break;
+ }
+ }
+
+ native_.callIfPossible(s._listenerCallback,
+ new Channel(result.channel.uri, result.channel.id),
+ payload, result.senderId);
+ }
+ break;
+ default:
+ console.log('Ignoring result type: [' + result_type + ']');
+ break;
+ }
+
+ /*
+ // TODO uncomment when implemented (or remove thid data from the protocol)
+ *var clientInfo = new ClientInfo(
+ result.clientInfo.isHost,
+ result.clientInfo.lientId,
+ result.clientInfo.connectionTime);*
+ var clientInfo = null;
+ */
+ }
+});
+
+AppCommunicationService.prototype.start = function(channel, successCallback, errorCallback) {
+ console.log('Entered AppCommunicationService.start()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'channel',
+ type: types_.PLATFORM_OBJECT,
+ values: tizen.Channel,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ // TODO check if the service is connected and started
+ // Raise the exception instead
+
+ var lid = this._serviceId;
+ this._startCallback = successCallback;
+ convergenceServices[lid] = this;
+
+ var result = native_.call('AppCommunicationService_start', {
+ deviceId: this._deviceId,
+ curListenerId: lid,
+ channel_data: channel
+ }, function(result) {
+ if (native_.isFailure(result))
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+AppCommunicationService.prototype.stop = function(channel, successCallback, errorCallback) {
+ console.log('Entered AppCommunicationService.stop()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'channel',
+ type: types_.PLATFORM_OBJECT,
+ values: tizen.Channel,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ // TODO check if the service is connected and started
+ // Raise the exception instead
+
+ var lid = -1;
+ if (successCallback) {
+ lid = this._serviceId;
+ this._stopCallback = successCallback;
+ convergenceServices[lid] = this;
+ }
+
+ var result = native_.call('AppCommunicationService_stop', {
+ deviceId: this._deviceId,
+ curListenerId: lid,
+ channel_data: channel
+ }, function(result) {
+ if (native_.isFailure(result))
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+AppCommunicationService.prototype.send = function(channel, payload, successCallback, errorCallback) {
+ console.log('Entered AppCommunicationService.send()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'channel',
+ type: types_.PLATFORM_OBJECT,
+ values: tizen.Channel,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'payload',
+ type: types_.PLATFORM_OBJECT,
+ values: [tizen.PayloadString, tizen.PayloadRawBytes],
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ // TODO check if the service is connected and started
+ // Raise the exception instead
+
+ var lid = this._serviceId;
+ this._sendCallback = successCallback;
+ convergenceServices[lid] = this;
+
+ var result = native_.call('AppCommunicationService_send', {
+ deviceId: this._deviceId,
+ curListenerId: lid,
+ channel_data: channel,
+ payload: payload
+ }, function(result) {
+ if (native_.isFailure(result))
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+AppCommunicationService.prototype.addListener = function(listenerCallback) {
+ console.log('Entered AppCommunicationService.addListener()');
+ var args = validator_.validateArgs(arguments, [
+ {name: 'listenerCallback', type: types_.FUNCTION}
+ ]);
+
+ var lid = this._serviceId;
+ // TODO in fact, it should be even the list of callbacks instead of
+ // the single callback
+ this._listenerCallback = listenerCallback;
+ convergenceServices[lid] = this;
+
+ console.log('');
+ console.log('AppCommunicationServiceCommandListeners ADDED [' + lid + ']');
+ console.log('');
+
+ var result = native_.callSync('AppCommunicationService_addListener', {
+ deviceId: this._deviceId,
+ curListenerId: lid
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+
+ return args.curListenerId; // TODO return proper index of listener
+};
+
+AppCommunicationService.prototype.removeListener = function(id) {
+ console.log('Entered AppCommunicationService.removeListener()');
+ var args = validator_.validateArgs(arguments, [
+ {name: 'id', type: types_.LONG, optional: false}
+ ]);
+
+ var result = native_.callSync('AppCommunicationService_removeListener', {
+ deviceId: this._deviceId
+ //curListenerId: id // not needed in below layers
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+
+ var lid = this._serviceId;
+ if (this._listenerCallback) {// TODO extend this to manage the list of callbacks
+ //delete this._listenerCallback;
+ this._listenerCallback = null;
+ }
+ convergenceServices[lid] = this;
+};
+
+function AppCommunicationServerService() {
+ console.log('Entered AppCommunicationServerService.constructor()');
+
+ validator_.isConstructorCall(this, AppCommunicationServerService);
+
+ this.connectionState = ConnectionState.NOT_CONNECTED;
+
+ native_.callSync('AppCommunicationServerService_constructLocal', {
+ deviceId: this._deviceId
+ });
+}
+
+AppCommunicationServerService.prototype = new AppCommunicationService();
+
+function AppCommunicationClientService() {
+ console.log('Entered AppCommunicationClientService.constructor()');
+
+ validator_.isConstructorCall(this, AppCommunicationClientService);
+
+ this.connectionState = ConnectionState.NOT_CONNECTED;
+}
+
+AppCommunicationClientService.prototype = new AppCommunicationService();
+
+AppCommunicationClientService.prototype.connect = function(successCallback, errorCallback) {
+ console.log('Entered AppCommunicationClientService.connect()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: false,
+ nullable: false
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ if (this.serviceState == ConnectionState.CONNECTED)
+ throw new WebAPIException('InvalidStateError', 'Service is connected already.');
+
+ var lid = this._serviceId;
+ this._connectCallback = successCallback;
+ convergenceServices[lid] = this;
+
+ var result = native_.call('AppCommunicationClientService_connect', {
+ deviceId: this._deviceId,
+ curListenerId: lid
+ }, function(result) {
+ if (native_.isFailure(result))
+ native_.callIfPossible(errorCallback, native_.getErrorObject(result));
+ });
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+};
+
+AppCommunicationClientService.prototype.disconnect = function(successCallback, errorCallback) {
+ console.log('Entered AppCommunicationClientService.disconnect()');
+
+ var args = validator_.validateArgs(arguments, [
+ {
+ name: 'successCallback',
+ type: types_.FUNCTION,
+ //values: ConnectSuccessCallback,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCallback',
+ type: types_.FUNCTION,
+ //values: ErrorCallback,
+ optional: true,
+ nullable: true
+ }
+ ]);
+ if (this.serviceState != ConnectionState.CONNECTED)
+ throw new WebAPIException('InvalidStateError', 'Service is not connected yet.');
+
+ var result = native_.callSync('AppCommunicationClientService_disconnect', {
+ deviceId: this._deviceId
+ });
+
+ if (native_.isFailure(result))
+ throw native_.getErrorObject(result);
+ else
+ connectionState = ConnectionState.DISCONNECTED;
+
+ native_.callIfPossible(successCallback, this);
+};
+
+function Channel(uri, id) {
+ validator_.isConstructorCall(this, Channel);
+ this.uri = uri;
+ this.id = id;
+}
+
+function PayloadString(key, value) {
+ validator_.isConstructorCall(this, PayloadString);
+ this.key = key;
+ this.value = value;
+ SetReadOnlyProperty(this, 'type', PayloadType.STRING); // read only property
+}
+
+function PayloadRawBytes(key, value) {
+ validator_.isConstructorCall(this, PayloadRawBytes);
+ this.key = key;
+ this.value = value;
+ SetReadOnlyProperty(this, 'type', PayloadType.RAW_BYTES); // read only property
+}
+
+function ClientInfo(isHost, clientId, connectionTime) {
+ validator_.isConstructorCall(this, ClientInfo);
+ this.isHost = isHost;
+ this.clientId = clientId;
+ this.connectionTime = connectionTime;
+}
+
+exports = new ConvergenceManager();
+tizen.RemoteAppControlService = RemoteAppControlService;
+tizen.AppCommunicationServerService = AppCommunicationServerService;
+tizen.AppCommunicationClientService = AppCommunicationClientService;
+tizen.Channel = Channel;
+tizen.PayloadString = PayloadString;
+tizen.PayloadRawBytes = PayloadRawBytes;
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_app_communication_service.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+#include <stdlib.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_channel.h"
+#include "convergence/convergence_payload.h"
+#include "convergence/convergence_client_info.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+using common::TizenResult;
+using common::TizenSuccess;
+
+namespace {
+// Payload data keys and some values
+static const std::string kPayload = "payload"; // ---
+
+// Service connection status keys
+static const std::string kServiceConnectionStatus = "connect_status"; // ---
+static const std::string kServiceConnectionStatusConnected = "service_connected";
+static const std::string kServiceConnectionStatusNotConnected = "service_not_connected";
+
+// Service listener status keys
+static const std::string kServiceListenerStatus = "listener_status"; //---
+static const std::string kServiceListenerStatusOk = "listener_ok"; // ---
+static const std::string kServiceListenerStatusError = "listener_error"; //---
+static const std::string kServiceListenerError = "listener_error"; //---
+} // namespace
+
+ConvergenceAppCommunicationService::ConvergenceAppCommunicationService()
+ : ConvergenceService() {
+ ScopeLogger();
+}
+
+ConvergenceAppCommunicationService::ConvergenceAppCommunicationService(conv_device_h device, ConvergenceInstance *convergence_plugin)
+ : ConvergenceService(device, CONV_SERVICE_APP_TO_APP_COMMUNICATION, convergence_plugin) {
+ ScopeLogger();
+}
+
+ConvergenceAppCommunicationService::~ConvergenceAppCommunicationService() {
+ ScopeLogger();
+
+ // Release all memory, used by callback paramerers
+ for (size_t i = 0; i < callback_param_gc_.size(); i++) {
+ delete callback_param_gc_[i];
+ }
+ callback_param_gc_.clear();
+}
+
+common::TizenResult ConvergenceAppCommunicationService::Start(
+ ConvergenceChannel *channel,
+ const int cur_listener_id) {
+ ScopeLogger();
+
+ LoggerI("Starting service [0x%x] with handle [0x%x]", this, service_handle_);
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+LoggerI("1");
+
+ UpdateListener(cur_listener_id);
+
+LoggerI("2");
+
+
+ { // DBG
+ conv_channel_h ch = channel->GetHandle();
+ char *id = NULL;
+ conv_channel_get_string(ch, "channel_id", &id);
+ char *uri = NULL;
+ conv_channel_get_string(ch, "uri", &uri);
+ LoggerI("===== CHANNEL ID [%s] URI [%s]", id, uri);
+ }
+
+ const int error = conv_service_start(service_handle,
+ channel->GetHandle(), nullptr);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_start");
+ }
+
+LoggerI("3");
+ delete channel;
+LoggerI("4");
+ return TizenSuccess();
+}
+
+common::TizenResult ConvergenceAppCommunicationService::Stop(
+ ConvergenceChannel *channel,
+ const int cur_listener_id) {
+ ScopeLogger();
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+ UpdateListener(cur_listener_id);
+
+ const int error = conv_service_stop(service_handle,
+ channel->GetHandle(), nullptr);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_stop");
+ }
+
+ delete channel;
+ return TizenSuccess();
+}
+
+common::TizenResult ConvergenceAppCommunicationService::Send(
+ ConvergenceChannel *channel,
+ ConvergencePayloadArray *payload,
+ const int cur_listener_id) {
+ ScopeLogger();
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+ UpdateListener(cur_listener_id);
+
+ { // DBG
+ LoggerI("...PUBLISHING for service handle [0x0%x]", service_handle);
+
+ conv_service_e t = CONV_SERVICE_NONE;
+ int e = conv_service_get_type(service_handle, &t);
+ if (CONV_ERROR_NONE != e) {
+ trace_conv_error(e, __LINE__, "get service type");
+ }
+ LoggerI("....type [%d]", t);
+
+ char *sid = nullptr;
+ e = conv_service_get_property_string(service_handle, CONV_SERVICE_ID, &sid);
+ if (CONV_ERROR_NONE != e) {
+ trace_conv_error(e, __LINE__, "get service id");
+ }
+ LoggerI("....id [%s]", sid);
+ free(sid);
+
+ conv_channel_h ch = channel->GetHandle();
+ char *id = NULL;
+ conv_channel_get_string(ch, "channel_id", &id);
+ char *uri = NULL;
+ conv_channel_get_string(ch, "uri", &uri);
+ LoggerI("===== CHANNEL ID [%s] URI [%s]", id, uri);
+ }
+
+ const int error = conv_service_publish(service_handle,
+ channel->GetHandle(), payload->GetHandle());
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_publish");
+ } else {
+ LoggerI("PUBLISHED SUCCESSFULY listener is [%d]", cur_listener_id);
+ }
+
+ delete channel;
+ delete payload;
+ return TizenSuccess();
+}
+
+
+// TODO move to Payload class
+
+
+void ConvergenceAppCommunicationService::ServiceListenerCb(conv_service_h service_handle,
+ conv_channel_h channel_handle,
+ conv_error_e error, conv_payload_h result, void* user_data) {
+ ScopeLogger();
+
+ CallbackParam *callbackParam = static_cast<CallbackParam *>(user_data);
+ if (!callbackParam) {
+ LoggerE("ERROR! NULL user data in Service Listener Callback");
+ return;
+ }
+
+ // TODO Send all payload and channel to the JS layer and parse it there
+
+ // TODO parse the payload and fill the param
+ LoggerI("YAY! Got the Callback (TODO implement it)");
+
+ if (CONV_ERROR_NONE != error) { // Error occured during connection
+ picojson::object param;
+ param[kServiceListenerStatus] = picojson::value(kServiceListenerStatusError);
+ param[kServiceListenerError] = picojson::value(static_cast<double>(error));
+ callbackParam->plugin_->ReplyAsync(kAppCommunicationListenerCallback,
+ callbackParam->callback_id_, false, param);
+ return;
+ }
+
+ // Parse the payload
+ const std::string result_type = ConvergencePayloadArray::ExtractPayloadString(result, "result_type"); // TODO extract to constant kResultType = "result_type";
+ LoggerI("Callback type [%s]", result_type.c_str());
+
+ picojson::object param;
+ param[kServiceListenerStatus] = picojson::value(kServiceListenerStatusOk);
+ param["channel"] = ConvergenceChannel::ToJson(channel_handle);
+ param["result_type"] = picojson::value(result_type);
+
+ if (("onStart" == result_type)
+ || ("onPublish" == result_type)
+ || ("onStop" == result_type)) {
+ // The service doesn't send any callback with thie response
+ } else if ("onMessage" == result_type) {
+ param["senderId"] = picojson::value(
+ ConvergencePayloadArray::ExtractPayloadString(result, "from")); // Define the string as a constant
+ param["payload"] = ConvergencePayloadArray::ToJson(result);
+ } else if ("onConnect" == result_type) {
+ //param["clientInfo"] = ConvergenceClientInfo(result).ToJson();
+ //callbackParam->plugin_->ReplyAsync(kAppCommunicationClientServiceConnectCallback,
+ // callbackParam->callback_id_, true, param);
+ return;
+ } else if ("onClientConnect" == result_type) {
+ // TODO the service doesn't send any callback with thie response
+ return; // TODO
+ } else if ("onDisconnect" == result_type) {
+ return; // TODO
+ } else if ("onClientDisconnect" == result_type) {
+ return; // TODO
+ } else if ("onRead" == result_type) {
+ // TODO
+ } else {
+ // Unsupported payload type, ignoring it
+ LoggerE("ERROR: Unsupported payload type; ignored");
+ return;
+ }
+
+ callbackParam->plugin_->ReplyAsync(kAppCommunicationListenerCallback,
+ callbackParam->callback_id_, true, param);
+
+ // TODO Remove callbackParam from GC
+ // TODO delete callbackParam
+}
+
+void ConvergenceAppCommunicationService::UpdateListener(const int cur_listener_id) {
+ ScopeLogger();
+
+ // TODO make sure that callback is not called twice for the same listener
+
+ // TODO: make a garbage collection and release this memory when callback unset
+ // and when whole manager is destructed
+ CallbackParam *param = new CallbackParam(convergence_plugin_, cur_listener_id);
+ callback_param_gc_.push_back(param);
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return;
+ }
+
+ { // dbg
+ LoggerI("...found service handle [%x0x]", service_handle);
+
+ conv_service_e t = CONV_SERVICE_NONE;
+ int e = conv_service_get_type(service_handle, &t);
+ if (CONV_ERROR_NONE != e) {
+ trace_conv_error(e, __LINE__, "get service type");
+ }
+ LoggerI("....type [%d]", t);
+
+ char *sid = nullptr;
+ e = conv_service_get_property_string(service_handle, CONV_SERVICE_ID, &sid);
+ if (CONV_ERROR_NONE != e) {
+ trace_conv_error(e, __LINE__, "get service id");
+ }
+ LoggerI("....id [%s]", sid);
+ free(sid);
+
+ char *sver = nullptr;
+ e = conv_service_get_property_string(service_handle, CONV_SERVICE_VERSION, &sver);
+ if (CONV_ERROR_NONE != e) {
+ trace_conv_error(e, __LINE__, "get service version");
+ }
+ LoggerI("....ver [%s]", sver);
+ free(sver);
+ }
+
+ const int error = conv_service_set_listener_cb(service_handle, ServiceListenerCb, param);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_set_listener_cb");
+ } else {
+ LoggerI("APP COMMUNICATION SERVICE LISTENER SET SUCCESSFULY [%d]", cur_listener_id);
+ }
+}
+
+common::TizenResult ConvergenceAppCommunicationService::SetListener(const int cur_listener_id) {
+ ScopeLogger();
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle)
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+
+ UpdateListener(cur_listener_id);
+
+ return TizenSuccess();
+}
+
+common::TizenResult ConvergenceAppCommunicationService::RemoveListener() {
+ ScopeLogger();
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+ const int error = conv_service_unset_listener_cb(service_handle);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_set_listener_cb");
+ return LogAndCreateTizenError(NotFoundError,
+ "Unset Listener Failed");
+ }
+
+ return TizenSuccess();
+}
+
+picojson::value ConvergenceAppCommunicationService::PayloadToJson(conv_payload_h payload) {
+ ScopeLogger();
+ picojson::value payload_json;
+
+ // TODO convert payload to array of ApplicationControlData
+
+ return payload_json;
+}
+
+
+
+ConvergenceAppCommunicationServerService::ConvergenceAppCommunicationServerService()
+ : ConvergenceAppCommunicationService() {
+ ScopeLogger();
+}
+
+ConvergenceAppCommunicationServerService::ConvergenceAppCommunicationServerService(
+ conv_device_h device, ConvergenceInstance *convergence_plugin)
+ : ConvergenceAppCommunicationService(device, convergence_plugin) {
+ ScopeLogger();
+
+ // Creating the handle of local service instance
+ int error = conv_service_create(&service_handle_);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_create App Comm Service");
+ }
+
+ error = conv_service_set_type(service_handle_, CONV_SERVICE_APP_TO_APP_COMMUNICATION);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_set_type App Comm Service");
+ }
+
+ /*
+ * Consider a constructor of App Communication Server Service with parameters:
+ * - Id
+ * - Version
+ */
+
+ error = conv_service_set_property_string(service_handle_, CONV_SERVICE_ID, "test_app"); // TODO set a proper service ID
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_set_property Id");
+ }
+
+ error = conv_service_set_property_string(service_handle_, CONV_SERVICE_VERSION, "1.0");
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_set_property Version");
+ }
+}
+
+ConvergenceAppCommunicationServerService::~ConvergenceAppCommunicationServerService() {
+ ScopeLogger();
+}
+
+common::TizenResult ConvergenceAppCommunicationServerService::Start(
+ ConvergenceChannel *channel,
+ const int cur_listener_id) {
+ ScopeLogger();
+
+
+ /* By implementation, the local App Communication Service doesn't send
+ * the callback confirming that the Start is successful.
+ * So we are sending this callback manually
+ */
+ picojson::object param;
+ param[kServiceListenerStatus] = picojson::value(kServiceListenerStatusOk);
+
+ // The object 'channel' will be deleted in the super::Start() so we should
+ // add its json before
+ param["channel"] = ConvergenceChannel::ToJson(channel->GetHandle()); // Define string as constant
+ param["result_type"] = picojson::value("onStart");
+
+ common::TizenResult result = ConvergenceAppCommunicationService::Start(
+ channel, cur_listener_id);
+
+ // TODO check if result value is OK
+
+ convergence_plugin_->ReplyAsync(kAppCommunicationListenerCallback,
+ cur_listener_id, true, param);
+ return result;
+}
+
+common::TizenResult ConvergenceAppCommunicationServerService::Stop(
+ ConvergenceChannel *channel,
+ const int cur_listener_id) {
+ ScopeLogger();
+
+ /* By implementation, the local App Communication Service doesn't send
+ * the callback confirming that the Start is successful.
+ * So we are sending this callback manually
+ */
+ picojson::object param;
+ param[kServiceListenerStatus] = picojson::value(kServiceListenerStatusOk);
+
+ // The object 'channel' will be deleted in the super::Start() so we should
+ // add its json before
+ param["channel"] = ConvergenceChannel::ToJson(channel->GetHandle());
+ param["result_type"] = picojson::value("onStop");
+
+ common::TizenResult result = ConvergenceAppCommunicationService::Stop(
+ channel, cur_listener_id);
+
+ // TODO check if result value is OK
+
+ convergence_plugin_->ReplyAsync(kAppCommunicationListenerCallback,
+ cur_listener_id, true, param);
+ return result;
+}
+
+ConvergenceAppCommunicationClientService::ConvergenceAppCommunicationClientService()
+ : ConvergenceAppCommunicationService() {
+ ScopeLogger();
+}
+
+ConvergenceAppCommunicationClientService::ConvergenceAppCommunicationClientService(
+ conv_device_h device, ConvergenceInstance *convergence_plugin)
+ : ConvergenceAppCommunicationService(device, convergence_plugin) {
+ ScopeLogger();
+}
+
+ConvergenceAppCommunicationClientService::~ConvergenceAppCommunicationClientService() {
+ ScopeLogger();
+}
+
+void ConvergenceAppCommunicationClientService::ServiceConnectedCb(conv_service_h service_handle,
+ conv_error_e error, conv_payload_h result, void* user_data) {
+ ScopeLogger();
+
+ CallbackParam *callbackParam = static_cast<CallbackParam *>(user_data);
+ if (!callbackParam) {
+ LoggerE("ERROR! NULL user data in Service Connect Callback");
+ return;
+ }
+
+ picojson::object param;
+ param[kPayload] = ConvergenceAppCommunicationService::PayloadToJson(result);
+ param["result_type"] = picojson::value("Connected");
+
+ if (CONV_ERROR_NONE == error) {
+ param[kServiceConnectionStatus] = picojson::value(kServiceConnectionStatusConnected);
+ callbackParam->plugin_->ReplyAsync(kAppCommunicationListenerCallback,
+ callbackParam->callback_id_,
+ true,
+ param);
+ } else {
+ // Error occured during connection
+ param[kServiceConnectionStatus] = picojson::value(kServiceConnectionStatusNotConnected);
+ callbackParam->plugin_->ReplyAsync(kAppCommunicationListenerCallback,
+ callbackParam->callback_id_,
+ false,
+ param);
+ }
+}
+
+common::TizenResult ConvergenceAppCommunicationClientService::Connect(const int cur_listener_id) {
+ ScopeLogger();
+
+ conv_service_h service = FindServiceHandle();
+ if (!service) {
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+ // TODO: make a garbage collection and release this memory when service is disconnected
+ // and when whole manager is destructed
+ CallbackParam *param = new CallbackParam(convergence_plugin_, cur_listener_id);
+ callback_param_gc_.push_back(param);
+
+ const int error = conv_service_connect(service, ServiceConnectedCb, param);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_connect");
+ }
+
+ return TizenSuccess();
+}
+
+common::TizenResult ConvergenceAppCommunicationClientService::Disconnect() {
+ ScopeLogger();
+
+ conv_service_h service = FindServiceHandle();
+ if (!service)
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+
+ const int error = conv_service_disconnect(service);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_disconnect");
+ }
+
+ return TizenSuccess();
+}
+
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_APP_COMMUNICATION_SERVICE_H__
+#define CONVERGENCE_CONVERGENCE_APP_COMMUNICATION_SERVICE_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "convergence/convergence_service.h"
+#include "convergence/convergence_utils.h"
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceChannel;
+class ConvergencePayloadArray;
+
+class ConvergenceAppCommunicationService : public ConvergenceService {
+ public:
+ ConvergenceAppCommunicationService();
+ ConvergenceAppCommunicationService(conv_device_h device, ConvergenceInstance *convergence_plugin);
+ virtual ~ConvergenceAppCommunicationService();
+ ConvergenceAppCommunicationService(const ConvergenceAppCommunicationService&) = delete;
+ ConvergenceAppCommunicationService(ConvergenceAppCommunicationService&&) = delete;
+ ConvergenceAppCommunicationService& operator=(const ConvergenceAppCommunicationService&) = delete;
+ ConvergenceAppCommunicationService& operator=(ConvergenceAppCommunicationService&&) = delete;
+ public:
+ virtual common::TizenResult Start(ConvergenceChannel *channel,
+ const int cur_listener_id);
+ virtual common::TizenResult Stop(ConvergenceChannel *channel,
+ const int cur_listener_id);
+ virtual common::TizenResult Send(ConvergenceChannel *channel,
+ ConvergencePayloadArray *payload,
+ const int cur_listener_id);
+ common::TizenResult SetListener(const int cur_listener_id);
+ common::TizenResult RemoveListener();
+ protected:
+ static picojson::value PayloadToJson(conv_payload_h payload);
+ private:
+ void UpdateListener(const int cur_listener_id);
+ static void ServiceListenerCb(conv_service_h service_handle,
+ conv_channel_h channel_handle,
+ conv_error_e error, conv_payload_h result, void* user_data);
+
+ protected:
+ std::vector<CallbackParam *> callback_param_gc_;
+};
+
+class ConvergenceAppCommunicationServerService : public ConvergenceAppCommunicationService {
+ public:
+ ConvergenceAppCommunicationServerService();
+ ConvergenceAppCommunicationServerService(conv_device_h device, ConvergenceInstance *convergence_plugin);
+ virtual ~ConvergenceAppCommunicationServerService();
+ ConvergenceAppCommunicationServerService(const ConvergenceAppCommunicationServerService&) = delete;
+ ConvergenceAppCommunicationServerService(ConvergenceAppCommunicationServerService&&) = delete;
+ ConvergenceAppCommunicationServerService& operator=(const ConvergenceAppCommunicationServerService&) = delete;
+ ConvergenceAppCommunicationServerService& operator=(ConvergenceAppCommunicationServerService&&) = delete;
+
+ public:
+ virtual common::TizenResult Start(ConvergenceChannel *channel,
+ const int cur_listener_id);
+ virtual common::TizenResult Stop(ConvergenceChannel *channel,
+ const int cur_listener_id);
+};
+
+class ConvergenceAppCommunicationClientService : public ConvergenceAppCommunicationService {
+ public:
+ ConvergenceAppCommunicationClientService();
+ ConvergenceAppCommunicationClientService(conv_device_h device, ConvergenceInstance *convergence_plugin);
+ virtual ~ConvergenceAppCommunicationClientService();
+ ConvergenceAppCommunicationClientService(const ConvergenceAppCommunicationClientService&) = delete;
+ ConvergenceAppCommunicationClientService(ConvergenceAppCommunicationClientService&&) = delete;
+ ConvergenceAppCommunicationClientService& operator=(const ConvergenceAppCommunicationClientService&) = delete;
+ ConvergenceAppCommunicationClientService& operator=(ConvergenceAppCommunicationClientService&&) = delete;
+ public:
+ common::TizenResult Connect(const int cur_listener_id);
+ common::TizenResult Disconnect();
+ private:
+ static void ServiceConnectedCb(conv_service_h service_handle,
+ conv_error_e error, conv_payload_h result, void* user_data);
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_APP_COMMUNICATION_SERVICE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_channel.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_utils.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+namespace {
+// Channel keys
+static const std::string kId = "id"; // This id is used in arguments (comes from JS layer)
+static const std::string kChannelId = "channel_id"; // This id is used in the App Comm Service engine
+static const std::string kUri = "uri";
+} // namespace
+
+ConvergenceChannel::ConvergenceChannel()
+ : channel_handle_(nullptr) {
+ ScopeLogger();
+}
+
+ConvergenceChannel::ConvergenceChannel(const picojson::value &channel_json)
+ : channel_handle_(nullptr) {
+ ScopeLogger();
+ FromJson(channel_json);
+}
+
+ConvergenceChannel::~ConvergenceChannel() {
+ ScopeLogger();
+
+ if (channel_handle_) {
+ conv_channel_destroy(channel_handle_);
+ channel_handle_ = NULL;
+ }
+}
+
+conv_channel_h ConvergenceChannel::GetHandle() const {
+ ScopeLogger();
+ return channel_handle_;
+}
+
+
+void ConvergenceChannel::FromJson(const picojson::value &channel_json) {
+ ScopeLogger();
+ if (channel_json.is<picojson::null>()) {
+ LoggerE("ERROR: Channel json value is NULL");
+ return;
+ }
+
+ if (channel_handle_) {
+ conv_channel_destroy(channel_handle_);
+ channel_handle_ = NULL;
+ }
+
+ int error = conv_channel_create(&channel_handle_);
+ if ((CONV_ERROR_NONE != error) || !channel_handle_) {
+ trace_conv_error(error, __LINE__, "creating channel handle");
+ return;
+ }
+
+ const std::string id = channel_json.get(kId).to_str();
+ error = conv_channel_set_string(channel_handle_, kChannelId.c_str(), id.c_str());
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "setting channel string Id");
+ }
+
+ const std::string uri = channel_json.get(kUri).to_str();
+ error = conv_channel_set_string(channel_handle_, kUri.c_str(), uri.c_str());
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "setting channel string URI");
+ }
+}
+
+picojson::value ConvergenceChannel::ToJson(conv_channel_h channel_handle) {
+ ScopeLogger();
+
+ picojson::object channel_object;
+ if (!channel_handle) {
+ LoggerE("Error: trying to convert NULL channel handle to json");
+ return picojson::value(channel_object);
+ }
+
+ { // Extracting channel ID
+ char *id = nullptr;
+ const int error = conv_channel_get_string(channel_handle, kChannelId.c_str(), &id);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "getting channel string Id");
+ } else {
+ channel_object[kId] = picojson::value(id);
+ free(id);
+ }
+ }
+
+ { // Extracting channel URI
+ char *uri = nullptr;
+ const int error = conv_channel_get_string(channel_handle, kUri.c_str(), &uri);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "getting channel string URI");
+ } else {
+ channel_object[kUri] = picojson::value(uri);
+ free(uri);
+ }
+ };
+
+ return picojson::value(channel_object);
+}
+
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_CHANNEL_H__
+#define CONVERGENCE_CONVERGENCE_CHANNEL_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceChannel {
+
+ public:
+ ConvergenceChannel();
+ ConvergenceChannel(const picojson::value &channel_json);
+ virtual ~ConvergenceChannel();
+ ConvergenceChannel(const ConvergenceChannel&) = delete;
+ ConvergenceChannel(ConvergenceChannel&&) = delete;
+ ConvergenceChannel& operator=(const ConvergenceChannel&) = delete;
+ ConvergenceChannel& operator=(ConvergenceChannel&&) = delete;
+
+ public:
+ conv_channel_h GetHandle() const;
+ void FromJson(const picojson::value &channel_json);
+
+ public:
+ static picojson::value ToJson(conv_channel_h channel_handle);
+
+ private:
+ conv_channel_h channel_handle_;
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_CHANNEL_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_client_info.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+#include <stdlib.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_utils.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+namespace {
+// Service keys
+static const std::string kIsHost = "client_is_host";
+static const std::string kConnectionTime = "client_connect_time"; //--
+static const std::string kClientId = "client_id";
+} // namespace
+
+ConvergenceClientInfo::ConvergenceClientInfo()
+ : isHost_(false)
+ , connectionTime_(0) {
+ ScopeLogger();
+}
+
+ConvergenceClientInfo::ConvergenceClientInfo(conv_payload_h payload)
+ : isHost_(false)
+ , connectionTime_(0) {
+ ScopeLogger();
+
+ isHost_ = ExtractPayloadString(payload, "client_is_host") == "1";
+ connectionTime_ = atol(ExtractPayloadString(payload, "client_connect_time").c_str());
+ clientId_ = ExtractPayloadString(payload, "client_id").c_str();
+}
+
+ConvergenceClientInfo::~ConvergenceClientInfo() {
+ ScopeLogger();
+}
+
+std::string ConvergenceClientInfo::ExtractPayloadString(conv_payload_h payload, const char *key) {
+ ScopeLogger();
+ char *value = nullptr;
+ const int error = conv_payload_get_string(payload, key, &value);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_payload_get_string");
+ return "";
+ }
+
+ if (value) {
+ const std::string result = std::string(value);
+ free(value);
+ return result;
+ }
+ return "";
+}
+
+picojson::value ConvergenceClientInfo::ToJson() const {
+ ScopeLogger();
+ picojson::object clientInfo;
+ clientInfo["isHost"] = picojson::value(static_cast<double>(isHost_));
+ clientInfo["connectionTime"] = picojson::value(static_cast<double>(connectionTime_));
+ clientInfo["clientId"] = picojson::value(clientId_);
+ return picojson::value(clientInfo);
+}
+
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_CLIENT_INFO_H__
+#define CONVERGENCE_CONVERGENCE_CLIENT_INFO_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceClientInfo {
+ public:
+ ConvergenceClientInfo();
+ ConvergenceClientInfo(conv_payload_h payload);
+ virtual ~ConvergenceClientInfo();
+ ConvergenceClientInfo(const ConvergenceClientInfo&) = delete;
+ ConvergenceClientInfo(ConvergenceClientInfo&&) = delete;
+ ConvergenceClientInfo& operator=(const ConvergenceClientInfo&) = delete;
+ ConvergenceClientInfo& operator=(ConvergenceClientInfo&&) = delete;
+
+ public:
+ picojson::value ToJson() const;
+
+ private:
+ std::string ExtractPayloadString(conv_payload_h payload, const char *key);
+
+ private:
+ bool isHost_;
+ std::string clientId_;
+ long connectionTime_;
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_CLIENT_INFO_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_device.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_service.h"
+#include "convergence/convergence_remote_app_control_service.h"
+#include "convergence/convergence_app_communication_service.h"
+#include "convergence/convergence_utils.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+namespace {
+// Service keys
+static const std::string kId = "id";
+static const std::string kName = "name"; //--
+static const std::string kDeviceType = "profile";
+static const std::string kDeviceServices = "services";
+} // namespace
+
+ConvergenceDevice::ConvergenceDevice()
+ : device_handle_(nullptr)
+ , convergence_plugin_(NULL) {
+ ScopeLogger();
+}
+
+ConvergenceDevice::ConvergenceDevice(conv_device_h device, ConvergenceInstance *convergence_plugin)
+ : device_handle_(device)
+ , convergence_plugin_(convergence_plugin) {
+ ScopeLogger();
+}
+
+ConvergenceDevice::~ConvergenceDevice() {
+ ScopeLogger();
+
+ // Releasing all registered services
+ for (auto it = services_.begin(); it != services_.end(); ++it) {
+ delete it->second;
+ }
+ services_.clear();
+
+ conv_device_destroy(device_handle_);
+}
+
+std::string ConvergenceDevice::ExtractDevicePropery(const char *property) {
+ ScopeLogger();
+ char *value = nullptr;
+ const int error = conv_device_get_property_string(device_handle_, property, &value);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_device_get_property_string");
+ return "";
+ }
+
+ if (value) {
+ const std::string result = std::string(value);
+ free(value);
+ return result;
+ }
+ return "";
+}
+
+ConvergenceService *ConvergenceDevice::SwapService(const int service_type) {
+ ScopeLogger();
+ LoggerI("Swapping service of type [%d]", service_type);
+ if (services_.count(service_type) <= 0) {
+ switch(service_type) {
+ case CONV_SERVICE_APP_TO_APP_COMMUNICATION: {
+ services_[service_type] =
+ new ConvergenceAppCommunicationService(device_handle_,
+ convergence_plugin_);
+ break;
+ }
+ case CONV_SERVICE_REMOTE_APP_CONTROL: {
+ LoggerI("Adding Remote App Control service");
+ services_[service_type] =
+ new ConvergenceRemoteAppControlService(device_handle_,
+ convergence_plugin_);
+ break;
+ }
+ default: {
+ LoggerE("ERROR! UNKNOWN SERVICE TYPE [%d]", service_type);
+ return nullptr;
+ }
+ }
+ }
+ return services_[service_type];
+}
+
+ConvergenceService *ConvergenceDevice::RegisterLocalService(const int service_type) {
+ ScopeLogger();
+ LoggerI("Registering the local service of type [%d]", service_type);
+ if (services_.count(service_type) <= 0) {
+ switch(service_type) {
+ case CONV_SERVICE_APP_TO_APP_COMMUNICATION: {
+ services_[service_type] =
+ new ConvergenceAppCommunicationServerService(device_handle_,
+ convergence_plugin_);
+ LoggerI("Registered for local device [%s] the service [0x%0x] of type [%d]",
+ id_.c_str(), services_[service_type], CONV_SERVICE_APP_TO_APP_COMMUNICATION);
+ break;
+ }
+ default: {
+ LoggerE("ERROR! UNKNOWN SERVICE TYPE [%d]", service_type);
+ return nullptr;
+ }
+ }
+ }
+ return services_[service_type];
+}
+
+void ConvergenceDevice::ForEachServiceCb(conv_service_h service_handle,
+ void* user_data) {
+ ScopeLogger();
+ if (!service_handle || !user_data) {
+ LoggerE("ERROR! Invalid parameters of D2D API Callback");
+ return;
+ }
+ ConvergenceDevice *owner = static_cast<ConvergenceDevice *>(user_data);
+
+ // Extracting service type
+ conv_service_e type = CONV_SERVICE_NONE;
+ int error = conv_service_get_type(service_handle, &type);
+ if (CONV_ERROR_NONE != error) {
+ LoggerE("ERROR! D2D API Get Service Type error [%d]", error);
+ return;
+ }
+
+ ConvergenceService *s = owner->SwapService(type);
+ if (!s) {
+ LoggerE("ERROR! Cannot add NULL service");
+ return;
+ }
+
+ s->Refresh();
+}
+
+void ConvergenceDevice::Refresh() {
+ ScopeLogger();
+ // Getting device properties from handle
+ id_ = ExtractDevicePropery(CONV_DEVICE_ID);
+ name_ = ExtractDevicePropery(CONV_DEVICE_NAME);
+ type_ = ExtractDevicePropery(CONV_DEVICE_TYPE);
+
+ LoggerE("Refreshed device id [%s] name [%s] type [%s]",
+ id_.c_str(), name_.c_str(), type_.c_str());
+
+ // Extracting services
+ const int error = conv_device_foreach_service(device_handle_, ForEachServiceCb, this);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_device_foreach_service");
+ }
+}
+
+picojson::value ConvergenceDevice::ToJson() const {
+ ScopeLogger();
+ picojson::object device_json;
+
+ // Convert device props and services into JSON
+ device_json[kId] = picojson::value(id_);
+ device_json[kName] = picojson::value(name_);
+ device_json[kDeviceType] = picojson::value(type_);
+
+ picojson::array services;
+ for (auto it = services_.begin(); it != services_.end(); ++it) {
+ ConvergenceService *s = it->second;
+ services.push_back(s->ToJson());
+ }
+ device_json[kDeviceServices] = picojson::value(services);
+
+ return picojson::value(device_json);
+}
+
+ConvergenceService *ConvergenceDevice::GetService(const int service_type) const {
+ ScopeLogger();
+ if (services_.count(service_type) <= 0)
+ return nullptr;
+ else
+ return services_[service_type];
+}
+
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_DEVICE_H__
+#define CONVERGENCE_CONVERGENCE_DEVICE_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceInstance;
+class ConvergenceService;
+
+class ConvergenceDevice {
+
+ public:
+ ConvergenceDevice();
+ ConvergenceDevice(conv_device_h device_handle, ConvergenceInstance *convergence_plugin);
+ virtual ~ConvergenceDevice();
+ ConvergenceDevice(const ConvergenceDevice&) = delete;
+ ConvergenceDevice(ConvergenceDevice&&) = delete;
+ ConvergenceDevice& operator=(const ConvergenceDevice&) = delete;
+ ConvergenceDevice& operator=(ConvergenceDevice&&) = delete;
+
+
+ public:
+ void Refresh();
+ ConvergenceService *GetService(const int service_type) const;
+ //picojson::object ToJson() const;
+ picojson::value ToJson() const;
+ //std::string get_device() const {return device_handle_; }
+
+ public:
+ ConvergenceService *RegisterLocalService(const int service_type);
+ void SetId(const std::string &id) { id_ = id; }
+
+ private:
+ ConvergenceService *SwapService(const int service_type);
+ std::string ExtractDevicePropery(const char *property);
+ static void ForEachServiceCb(conv_service_h service_handle, void* user_data);
+
+ private:
+ conv_device_h device_handle_;
+ ConvergenceInstance *convergence_plugin_;
+ mutable std::unordered_map<int, ConvergenceService *> services_;
+
+ private:
+ std::string id_;
+ std::string name_;
+ std::string type_; // Device profile: mobile, wearable, TV
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_DEVICE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "convergence/convergence_extension.h"
+
+#include "convergence/convergence_instance.h"
+
+// This will be generated from convergence_api.js
+extern const char kSource_convergence_api[];
+
+common::Extension* CreateExtension() {
+ return new ConvergenceExtension;
+}
+
+ConvergenceExtension::ConvergenceExtension() {
+ SetExtensionName("tizen.convergence");
+ SetJavaScriptAPI(kSource_convergence_api);
+
+ const char* entry_points[] = {
+ "tizen.RemoteAppControlService",
+ "tizen.AppCommunicationServerService",
+ "tizen.AppCommunicationClientService",
+ "tizen.Channel",
+ "tizen.PayloadString",
+ "tizen.PayloadRawBytes",
+ nullptr
+ };
+ SetExtraJSEntryPoints(entry_points);
+}
+
+ConvergenceExtension::~ConvergenceExtension() {}
+
+common::Instance* ConvergenceExtension::CreateInstance() {
+ return new extension::convergence::ConvergenceInstance;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_EXTENSION_H_
+#define CONVERGENCE_CONVERGENCE_EXTENSION_H_
+
+#include "common/extension.h"
+
+class ConvergenceExtension : public common::Extension {
+ public:
+ ConvergenceExtension();
+ virtual ~ConvergenceExtension();
+
+ private:
+ virtual common::Instance* CreateInstance();
+};
+
+#endif // CONVERGENCE_CONVERGENCE_EXTENSION_H_
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "convergence/convergence_instance.h"
+
+#include <functional>
+#include <string>
+
+#include "convergence/convergence_manager.h"
+#include "convergence/convergence_remote_app_control_service.h"
+#include "convergence/convergence_app_communication_service.h"
+#include "convergence/convergence_channel.h"
+#include "convergence/convergence_payload.h"
+#include "common/logger.h"
+#include "common/picojson.h"
+#include "common/task-queue.h"
+#include "common/tools.h"
+
+
+namespace extension {
+namespace convergence {
+
+namespace {
+// The privileges that required in Convergence API
+const std::string kPrivilegeInternet = "http://tizen.org/privilege/internet";
+const std::string kPrivilegeBluetooth = "http://tizen.org/privilege/bluetooth";
+const std::string kPrivilegeWifiDirect = "http://tizen.org/privilege/wifidirect";
+
+// JS listener keys
+static const std::string kJSListenerStatus = "status";
+static const std::string kJSCurrentListenerId = "curListenerId";
+static const std::string kJSTargetListenerId = "listenerId";
+static const std::string kSuccess = "success";
+static const std::string kError = "error";
+
+// Arguments, passed from JS
+static const std::string kJSCallbackId = "callbackId";
+static const std::string kJSArgumentDeviceId = "deviceId";
+static const std::string kJSArgumentServiceTypeNumber = "serviceTypeNumber";
+static const std::string kJSArgumentChannel = "channel_data";
+static const std::string kJSArgumentPayload = "payload";
+static const std::string kJSArgumentAppId = "appId";
+static const std::string kJSArgumentReply = "reply";
+static const std::string kJSArgumentTimeout = "timeout";
+static const std::string kJSArgumentService = "service";
+} // namespace
+
+using namespace common;
+
+ConvergenceInstance::ConvergenceInstance() {
+ using namespace std::placeholders;
+ #define REGISTER_SYNC(c,x) \
+ RegisterSyncHandler(c, std::bind(&ConvergenceInstance::x, this, _1, _2));
+ REGISTER_SYNC("ConvergenceManager_stopDiscovery",
+ ConvergenceManagerStopDiscovery);
+
+ REGISTER_SYNC("AppCommunicationService_addListener", AppCommunicationServiceAddListener);
+ REGISTER_SYNC("AppCommunicationService_removeListener", AppCommunicationServiceRemoveListener);
+ //REGISTER_SYNC("Service_createLocalService", ServiceCreateLocal);
+ #undef REGISTER_SYNC
+ #define REGISTER_ASYNC(c,x) \
+ RegisterSyncHandler(c, std::bind(&ConvergenceInstance::x, this, _1, _2));
+ REGISTER_ASYNC("ConvergenceManager_startDiscovery",
+ ConvergenceManagerStartDiscovery);
+
+ REGISTER_ASYNC("RemoteAppControlService_connect", RemoteAppControlServiceConnect);
+ REGISTER_ASYNC("RemoteAppControlService_disconnect", RemoteAppControlServiceDisconnect);
+ REGISTER_ASYNC("RemoteAppControlService_launch", RemoteAppControlServiceLaunch);
+
+ REGISTER_ASYNC("AppCommunicationService_start", AppCommunicationServiceStart);
+ REGISTER_ASYNC("AppCommunicationService_stop", AppCommunicationServiceStop);
+ REGISTER_ASYNC("AppCommunicationService_send", AppCommunicationServiceSend);
+
+ REGISTER_ASYNC("AppCommunicationServerService_constructLocal", AppCommunicationServerServiceConstructLocal);
+
+ REGISTER_ASYNC("AppCommunicationClientService_connect", AppCommunicationClientServiceConnect);
+ REGISTER_ASYNC("AppCommunicationClientService_disconnect", AppCommunicationClientServiceDisconnect);
+ #undef REGISTER_ASYNC
+}
+
+ConvergenceInstance::~ConvergenceInstance() {
+}
+
+void ConvergenceInstance::ReplyAsync(ConvergenceCallbacks callback_function_type,
+ int curListenerId, bool isSuccess, picojson::object& param) {
+ ScopeLogger();
+
+ param[kJSListenerStatus] = picojson::value(isSuccess ? kSuccess : kError);
+ param[kJSCurrentListenerId] = picojson::value(static_cast<double>(curListenerId));
+
+ switch(callback_function_type) {
+ case kConvergenceManagerDiscoveryCallback: {
+ param[kJSTargetListenerId] = picojson::value("CONVERGENCE_DISCOVERY_LISTENER");
+ break;
+ }
+ /*case kRemoteAppControlServiceConnectCallback: {
+ param[kJSTargetListenerId] =
+ picojson::value("REMOTE_APP_CONTROL_SERVICE_CONNECT_LISTENER");
+ break;
+ }*/
+ case kRemoteAppControlListenerCallback: {
+ param[kJSTargetListenerId] =
+ picojson::value("REMOTE_APP_CONTROL_SERVICE_LISTENER");
+ break;
+ }
+ /*case kAppCommunicationSuccessCallback: {
+ param[kJSTargetListenerId] =
+ picojson::value("APP_COMMUNICATION_SERVICE_SUCCESS_LISTENER");
+ break;
+ }*/
+ case kAppCommunicationListenerCallback: {
+ param[kJSTargetListenerId] =
+ picojson::value("APP_COMMUNICATION_SERVICE_LISTENER");
+ break;
+ }
+ /*case kAppCommunicationClientServiceConnectCallback: {
+ param[kJSTargetListenerId] =
+ picojson::value("APP_COMMUNICATON_CLIENT_SERVICE_CONNECT_LISTENER");
+ break;
+ }*/
+ default: {
+ LoggerE("Invalid Callback Type");
+ return;
+ }
+ }
+
+ picojson::value result = picojson::value(param);
+ LoggerD("---> %s", result.serialize().c_str()); // TODO remove
+
+ PostMessage(result.serialize().c_str());
+}
+
+#define CHECK_EXIST(args, name, out) \
+ if (!args.contains(name)) {\
+ ReportError(TypeMismatchException(name" is required argument"), out);\
+ return;\
+ }
+
+void ConvergenceInstance::ConvergenceManagerStartDiscovery(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+ CHECK_EXIST(args, "timeout", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ LoggerI("ARGS: %s", args.serialize().c_str());
+
+ auto start_discovery =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("start_discovery");
+
+ // Start the discovery procedure
+ ConvergenceManager::GetInstance(this).StartDiscovery(
+ static_cast<long>(args.get(kJSArgumentTimeout).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto start_discovery_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("start_discovery_result");
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ start_discovery,
+ start_discovery_result,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::ConvergenceManagerStopDiscovery(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ // Running the discovery stop procedure
+ ConvergenceManager::GetInstance(this).StopDiscovery();
+ //out[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::RemoteAppControlServiceConnect(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ LoggerI("ARGS: %s", args.serialize().c_str());
+
+ auto connect =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("connect");
+
+ // Finding the service
+ ConvergenceRemoteAppControlService *service =
+ static_cast<ConvergenceRemoteAppControlService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_REMOTE_APP_CONTROL));
+ if (!service) {
+ LoggerE("Can not find the service type = 1, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ //ReportSuccess(object); // TODO ReportError
+ return;
+ }
+
+ // Running the service connect procedure
+ service->Connect(static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto connect_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("connect_result");
+
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ connect,
+ connect_result,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::RemoteAppControlServiceDisconnect(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ //LoggerI("ARGS: %s", args.serialize().c_str());
+
+ auto disconnect =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("disconnect");
+
+ // Finding the service
+ ConvergenceRemoteAppControlService *service =
+ static_cast<ConvergenceRemoteAppControlService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_REMOTE_APP_CONTROL));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 1, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service disconnect procedure
+ service->Disconnect();
+
+ picojson::object& object = result->get<picojson::object>();
+ ReportSuccess(object);
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Async<picojson::value>(
+ disconnect,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::RemoteAppControlServiceLaunch(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ auto launch = [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("send");
+
+ // Finding the service
+ ConvergenceRemoteAppControlService *service =
+ static_cast<ConvergenceRemoteAppControlService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_REMOTE_APP_CONTROL));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 1, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service app control procedure
+ service->Launch(
+ args.get(kJSArgumentAppId).to_str().c_str(),
+ static_cast<bool>(args.get(kJSArgumentReply).get<bool>()),
+ static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto launch_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("send_result");
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ launch,
+ launch_result,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationServiceStart(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ auto start = [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("start");
+
+ // Finding the service
+ ConvergenceAppCommunicationService *service =
+ static_cast<ConvergenceAppCommunicationService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 0, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service start procedure
+ service->Start(new ConvergenceChannel(args.get(kJSArgumentChannel)),
+ static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto start_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("start_result");
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ start,
+ start_result,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationServiceSend(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ auto send = [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("send");
+
+ // Finding the service
+ ConvergenceAppCommunicationService *service =
+ static_cast<ConvergenceAppCommunicationService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 0, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service send procedure
+ service->Send(new ConvergenceChannel(args.get(kJSArgumentChannel)),
+ new ConvergencePayloadArray(args.get(kJSArgumentPayload)),
+ static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto send_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("send_result");
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ send,
+ send_result,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationServiceStop(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ auto stop = [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("stop");
+
+ // Finding the service
+ ConvergenceAppCommunicationService *service =
+ static_cast<ConvergenceAppCommunicationService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 0, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service stop procedure
+ service->Stop(new ConvergenceChannel(args.get(kJSArgumentChannel)),
+ static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto stop_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("stop_result");
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ stop,
+ stop_result,
+ data);
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationServiceAddListener(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ LoggerI("ARGS: %s", args.serialize().c_str());
+
+ // Finding the service
+ ConvergenceAppCommunicationService *service =
+ static_cast<ConvergenceAppCommunicationService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 0, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service stop procedure
+ service->SetListener(static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationServiceRemoveListener(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ // Finding the service
+ ConvergenceAppCommunicationService *service =
+ static_cast<ConvergenceAppCommunicationService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 0, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service stop procedure
+ service->RemoveListener();
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationServerServiceConstructLocal(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ // Finding the service
+ ConvergenceAppCommunicationClientService *service =
+ static_cast<ConvergenceAppCommunicationClientService *>(
+ ConvergenceManager::GetInstance(this).RegisterLocalService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 1, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationClientServiceConnect(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_EXIST(args, "callbackId", out)
+
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ LoggerI("ARGS: %s", args.serialize().c_str());
+
+ auto connect =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("connect");
+
+ // Finding the service
+ ConvergenceAppCommunicationClientService *service =
+ static_cast<ConvergenceAppCommunicationClientService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ LoggerE("Can not find the service type = 1, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ //ReportSuccess(object); // TODO ReportError
+ return;
+ }
+
+ // Running the service connect procedure
+ service->Connect(static_cast<int>(args.get(kJSCurrentListenerId).get<double>()));
+
+ picojson::object& object = result->get<picojson::object>();
+ object[kJSCallbackId] = args.get(kJSCallbackId);
+ ReportSuccess(object);
+ };
+
+ auto connect_result =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("connect_result");
+
+ result->get<picojson::object>()[kJSCallbackId] = args.get(kJSCallbackId);
+ Instance::PostMessage(this, result->serialize().c_str());
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ connect,
+ connect_result,
+ data);
+ ReportSuccess(out);
+}
+
+void ConvergenceInstance::AppCommunicationClientServiceDisconnect(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ /*CHECK_PRIVILEGE_ACCESS(kPrivilegeInternet, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out)
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeWifiDirect, &out)*/
+
+ //LoggerI("ARGS: %s", args.serialize().c_str());
+
+ auto disconnect =
+ [this, args](const std::shared_ptr<picojson::value>& result) {
+ ScopeLogger("disconnect");
+
+ // Finding the service
+ ConvergenceAppCommunicationClientService *service =
+ static_cast<ConvergenceAppCommunicationClientService *>(
+ ConvergenceManager::GetInstance(this).GetService(args.get(kJSArgumentDeviceId).to_str().c_str(),
+ CONV_SERVICE_APP_TO_APP_COMMUNICATION));
+ if (!service) {
+ //ReportSuccess(object); // TODO ReportError
+ LoggerE("Can not find the service type = 1, device_id = ",
+ args.get(kJSArgumentDeviceId).to_str().c_str());
+ return;
+ }
+
+ // Running the service disconnect procedure
+ service->Disconnect();
+
+ picojson::object& object = result->get<picojson::object>();
+ ReportSuccess(object);
+ };
+
+ auto data =
+ std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}};
+
+ TaskQueue::GetInstance().Async<picojson::value>(
+ disconnect,
+ data);
+ ReportSuccess(out);
+}
+
+
+#undef CHECK_EXIST
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_INSTANCE_H_
+#define CONVERGENCE_CONVERGENCE_INSTANCE_H_
+
+//#include "common/tizen_instance.h"
+#include "common/extension.h"
+
+namespace extension {
+namespace convergence {
+
+enum ConvergenceCallbacks {
+ // Convergence Manager Discovery
+ kConvergenceManagerDiscoveryCallback,
+
+ // Remote App Control
+ //kRemoteAppControlServiceConnectCallback,
+ kRemoteAppControlListenerCallback,
+
+ // App Communication
+ //kAppCommunicationSuccessCallback,
+ kAppCommunicationListenerCallback,
+
+
+ // App Communication Client
+ //kAppCommunicationClientServiceConnectCallback
+};
+
+
+// TODO: inherit it by common::TizenInstance class
+//class ConvergenceInstance : public common::TizenInstance {
+
+class ConvergenceInstance : public common::ParsedInstance {
+ public:
+ ConvergenceInstance();
+ virtual ~ConvergenceInstance();
+ public:
+ void ReplyAsync(ConvergenceCallbacks cbfunc,
+ int curListenerId, bool isSuccess, picojson::object& param);
+
+ private:
+ // TODO: make all API functions return common::TizenResult
+
+ // Convergence Manager
+ void ConvergenceManagerStartDiscovery(const picojson::value& args,
+ picojson::object& out);
+ void ConvergenceManagerStopDiscovery(const picojson::value& args,
+ picojson::object& out);
+
+ // Remote App Control Service
+ void RemoteAppControlServiceConnect(const picojson::value& args, picojson::object& out);
+ void RemoteAppControlServiceDisconnect(const picojson::value& args, picojson::object& out);
+ void RemoteAppControlServiceLaunch(const picojson::value& args, picojson::object& out);
+
+ // App Communication Service
+ void AppCommunicationServiceStart(const picojson::value& args, picojson::object& out);
+ void AppCommunicationServiceStop(const picojson::value& args, picojson::object& out);
+ void AppCommunicationServiceSend(const picojson::value& args, picojson::object& out);
+ void AppCommunicationServiceAddListener(const picojson::value& args, picojson::object& out);
+ void AppCommunicationServiceRemoveListener(const picojson::value& args, picojson::object& out);
+
+ // App Communication Server Service
+ void AppCommunicationServerServiceConstructLocal(const picojson::value& args, picojson::object& out);
+
+ // App Communication Client Service
+ void AppCommunicationClientServiceConnect(const picojson::value& args, picojson::object& out);
+ void AppCommunicationClientServiceDisconnect(const picojson::value& args, picojson::object& out);
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_INSTANCE_H_
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "convergence/convergence_manager.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_device.h"
+#include "convergence/convergence_service.h"
+#include "convergence/convergence_utils.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+using common::TizenResult;
+using common::TizenSuccess;
+
+
+// TODO check which fields are needed
+// TODO remove dublications, marked with //---
+namespace {
+// Commonly used key words
+static const std::string kId = "id"; //---
+static const std::string kName = "name"; //--
+static const std::string kKey = "key";
+static const std::string kValue = "value";
+
+// Channel data keys
+static const std::string kChannel = "channel";
+static const std::string kChannelDataChannelId = "channel_id";
+static const std::string kChannelDataChannelOption = "option";
+static const std::string kChannelDataChannelOptions = "options";
+
+// Payload data keys and some values
+static const std::string kPayload = "payload"; // ---
+static const std::string kPayloadDataType = "type"; // String, bytes or app control
+static const std::string kTypeString = "STRING";
+static const std::string kTypeRawBytes = "RAW_BYTES";
+static const std::string kTypeAppControl = "APP_CONTROL";
+static const std::string kPayloadDataAppControlAppId = "appI";
+static const std::string kPayloadDataAppControlOperation = "operation";
+static const std::string kPayloadDataAppControlUri = "uri";
+static const std::string kPayloadDataAppControlMime = "mime";
+static const std::string kPayloadDataAppControlLaunchMode = "launch_mode";
+static const std::string kPayloadDataAppControlCategory = "category";
+
+// Service keys
+static const std::string kServiceType = "serviceType"; //---
+static const std::string kServiceConnectionState = "connectionState"; //---
+static const std::string kServiceProperties = "properties";
+
+// Device keys
+static const std::string kDevice = "device";
+static const std::string kDeviceType = "profile"; //---
+static const std::string kDeviceServices = "services"; //---
+
+// Discovery keys
+static const std::string kDiscoveryStatus = "discovery_status";
+static const std::string kDiscoveryStatusDeviceFound = "device_found";
+static const std::string kDiscoveryStatusFinished = "discovery_finished";
+static const std::string kDiscoveryStatusError = "discovery_error";
+static const std::string kDiscoveryError = "discovery_error";
+
+// Service connection status keys
+static const std::string kServiceConnectionStatus = "connect_status"; //---
+static const std::string kServiceConnectionStatusConnected = "service_connected"; //---
+static const std::string kServiceConnectionStatusNotConnected = "service_not_connected"; //---
+
+// Service listener status keys
+static const std::string kServiceListenerStatus = "listener_status"; //---
+static const std::string kServiceListenerStatusOk = "listener_ok"; // ---
+static const std::string kServiceListenerStatusError = "listener_error"; //---
+static const std::string kServiceListenerError = "listener_error"; //---
+} // namespace
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+ConvergenceManager &ConvergenceManager::GetInstance(
+ ConvergenceInstance *owner) {
+ static ConvergenceManager instance;
+ instance.convergence_plugin_ = owner;
+ return instance;
+}
+
+ConvergenceManager::ConvergenceManager()
+ : convergence_plugin_(nullptr)
+ , convergence_manager_(nullptr) {
+ ScopeLogger();
+ const int error = conv_create(&convergence_manager_);
+ if (CONV_ERROR_NONE != error) {
+ // Handle error
+ trace_conv_error(error, __LINE__, "conv_create");
+ }
+}
+
+ConvergenceManager::~ConvergenceManager() {
+ ScopeLogger();
+
+ // Releasing all registered devices
+ for (auto it = registered_devices_.begin(); it != registered_devices_.end(); ++it) {
+ delete it->second;
+ }
+ registered_devices_.clear();
+
+ int error = conv_destroy(convergence_manager_);
+ if (CONV_ERROR_NONE != error) {
+ // Handle error
+ trace_conv_error(error, __LINE__, "conv_destroy");
+ }
+ convergence_manager_ = nullptr;
+}
+
+ConvergenceDevice *ConvergenceManager::SwapDevice(const char *device_id,
+ conv_device_h device_handle) {
+ ScopeLogger();
+ if (registered_devices_.count(device_id) <= 0) {
+ ConvergenceDevice *d = new ConvergenceDevice(device_handle, convergence_plugin_);
+ d->SetId(device_id);
+ registered_devices_[device_id] = d;
+ LoggerI("...registering the device [%s, %x]", device_id, device_handle);
+ }
+ return registered_devices_[device_id];
+}
+
+void ConvergenceManager::DiscoveryCb(conv_device_h device_handle,
+ conv_discovery_result_e result, void* user_data) {
+ ScopeLogger();
+
+ if (!user_data) {
+ LoggerE("ERROR! NULL user data in discovery callback");
+ return;
+ }
+
+ ConvergenceManager *owner = static_cast<ConvergenceManager *>(user_data);
+
+ switch(result) {
+ case CONV_DISCOVERY_RESULT_SUCCESS: {
+ LoggerI("...found a device");
+
+ char *id = nullptr;
+ int error = conv_device_get_property_string(device_handle, CONV_DEVICE_ID, &id);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_device_get_property_string ID");
+ }
+ if (!id) {
+ LoggerE("BAD ERROR: Device ID is NULL");
+ return; // TODO report error
+ }
+
+ conv_device_h clone_device = nullptr;
+ error = conv_device_clone(device_handle, &clone_device);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_device_clone");
+ break;
+ }
+ ConvergenceDevice *d = owner->SwapDevice(id, clone_device);
+ free(id);
+
+ if (!d) {
+ // Handle bad error
+ LoggerE("BAD ERROR: Cannot swap the device");
+ break;
+ }
+
+ d->Refresh();
+
+ picojson::object param;
+ param[kDiscoveryStatus] = picojson::value(kDiscoveryStatusDeviceFound);
+ param[kDevice] = d->ToJson();
+ owner->convergence_plugin_->ReplyAsync(kConvergenceManagerDiscoveryCallback,
+ -1,
+ true,
+ param);
+
+ break;
+ }
+ case CONV_DISCOVERY_RESULT_FINISHED: {
+ LoggerE("...discovery finished");
+
+ picojson::object param;
+ param[kDiscoveryStatus] = picojson::value(kDiscoveryStatusFinished);
+ owner->convergence_plugin_->ReplyAsync(kConvergenceManagerDiscoveryCallback,
+ -1,
+ true,
+ param);
+ break;
+ }
+ case CONV_DISCOVERY_RESULT_ERROR: {
+ LoggerE("Discovery Error");
+ picojson::object param;
+ param[kDiscoveryStatus] = picojson::value(kDiscoveryStatusError);
+ param[kDiscoveryError] = picojson::value(static_cast<double>(result));
+ owner->convergence_plugin_->ReplyAsync(kConvergenceManagerDiscoveryCallback,
+ -1,
+ false,
+ param);
+ break;
+ }
+ default: {
+ LoggerE("Unknown discovery result");
+ break;
+ }
+ }
+}
+
+TizenResult ConvergenceManager::StartDiscovery(long timeout) {
+ ScopeLogger();
+ const int error = conv_discovery_start(convergence_manager_,
+ (const int)timeout, DiscoveryCb, this);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_discovery_start");
+ }
+ return TizenSuccess();
+}
+
+TizenResult ConvergenceManager::StopDiscovery() {
+ ScopeLogger();
+ const int error = conv_discovery_stop(convergence_manager_);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_discovery_stop");
+ }
+ return TizenSuccess();
+}
+
+//-------------
+// TODO Implement the NULL Object pattern for Service,
+// so this function would return always valid pointers
+//-------------
+ConvergenceService *ConvergenceManager::GetService(const char *device_id,
+ const int service_type) const {
+ ScopeLogger();
+
+ LoggerI("Getting the service object for id [%s], type [%d]", device_id, service_type);
+ if (registered_devices_.count(device_id) <= 0) {
+ LoggerE("Device ID not found");
+ return nullptr;
+ }
+
+ ConvergenceDevice *d = registered_devices_[device_id];
+ if (!d) {
+ LoggerE("Device object not found");
+ return nullptr;
+ }
+
+ return d->GetService(service_type);
+}
+
+ConvergenceService *ConvergenceManager::RegisterLocalService(const char *device_id,
+ const int service_type) {
+ ScopeLogger();
+
+ LoggerI("Registering local service [%d] for device id [%s]", service_type, device_id);
+
+ ConvergenceDevice *d = SwapDevice(device_id, nullptr);
+ if (!d) {
+ LoggerE("Device object not found");
+ return nullptr;
+ }
+
+ return d->RegisterLocalService(service_type);
+}
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_MANAGER_H__
+#define CONVERGENCE_CONVERGENCE_MANAGER_H__
+
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+
+class ConvergenceDevice;
+class ConvergenceService;
+
+// TODO rename to Discovery Manager
+// TODO extract service start, stop, read, send to Service Manager class
+class ConvergenceManager {
+
+ public:
+ static ConvergenceManager &GetInstance(class ConvergenceInstance *owner);
+
+ public:
+ ConvergenceManager();
+ ~ConvergenceManager();
+ ConvergenceManager(const ConvergenceManager&) = delete;
+ ConvergenceManager(ConvergenceManager&&) = delete;
+ ConvergenceManager& operator=(const ConvergenceManager&) = delete;
+ ConvergenceManager& operator=(ConvergenceManager&&) = delete;
+
+ public:
+ common::TizenResult StartDiscovery(long timeout);
+ common::TizenResult StopDiscovery();
+
+ public:
+ ConvergenceService *GetService(const char *device_id,
+ const int service_type) const;
+ ConvergenceService *RegisterLocalService(const char *device_id,
+ const int service_type);
+
+ private:
+ static void DiscoveryCb(conv_device_h device_handle,
+ conv_discovery_result_e result, void* user_data);
+ ConvergenceDevice *SwapDevice(const char *device_id,
+ conv_device_h device_handle);
+
+ private:
+ class ConvergenceInstance *convergence_plugin_;
+ conv_h convergence_manager_;
+ mutable std::unordered_map<std::string, ConvergenceDevice *> registered_devices_; // TODO rename to discovered_devices_ or simply devices_
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_MANAGER_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_payload.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_utils.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+namespace {
+// Payload data keys and some values
+static const std::string kKey = "key";
+static const std::string kValue = "value";
+static const std::string kPayloadDataType = "type"; // String, bytes
+static const std::string kTypeString = "STRING";
+static const std::string kTypeRawBytes = "RAW_BYTES";
+} // namespace
+
+ConvergencePayloadArray::ConvergencePayloadArray()
+ : payload_handle_(nullptr) {
+ ScopeLogger();
+}
+
+ConvergencePayloadArray::ConvergencePayloadArray(const picojson::value &payload_json)
+ : payload_handle_(nullptr) {
+ ScopeLogger();
+ FromJson(payload_json);
+}
+
+ConvergencePayloadArray::~ConvergencePayloadArray() {
+ ScopeLogger();
+
+ if (payload_handle_) {
+ conv_payload_destroy(payload_handle_);
+ payload_handle_ = nullptr;
+ }
+}
+
+conv_payload_h ConvergencePayloadArray::GetHandle() const {
+ ScopeLogger();
+ return payload_handle_;
+}
+
+
+void ConvergencePayloadArray::FromJson(const picojson::value &payload_json) {
+ ScopeLogger();
+ if (payload_json.is<picojson::null>()) {
+ LoggerE("ERROR: trying to convert NULL payload json value");
+ return;
+ }
+
+ if (payload_handle_) {
+ conv_payload_destroy(payload_handle_);
+ payload_handle_ = nullptr;
+ }
+
+ int error = conv_payload_create(&payload_handle_);
+ if ((CONV_ERROR_NONE != error) || !payload_handle_) {
+ trace_conv_error(error, __LINE__, "creating payload handle");
+ return;
+ }
+
+ if (!payload_json.is<picojson::array>()) {
+ LoggerE("ERROR: Payload json is not an array");
+ return;
+ }
+
+ const picojson::array &payload_items = payload_json.get<picojson::array>();
+ for (size_t i = 0; i < payload_items.size(); i++) {
+ picojson::value item = payload_items[i];
+ const std::string type = item.get(kPayloadDataType).to_str();
+ if (kTypeString == type) {
+ const std::string key = item.get(kKey).to_str();
+ const std::string value = item.get(kValue).to_str(); // TODO: check if it is an object
+ int error = conv_payload_set_string(payload_handle_, key.c_str(), value.c_str());
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "setting payload string");
+ }
+ } else if (kTypeRawBytes == type) {
+ // TODO
+ LoggerW("IMPLEMENT BYTE PAYLOAD!!!");
+ } else {
+ LoggerE("ERROR! Unknown type of payload [%s]", type.c_str());
+ }
+ }
+}
+
+picojson::value ConvergencePayloadArray::ToJson(conv_payload_h payload_handle) {
+ ScopeLogger();
+
+ picojson::array payloads; // Array of payloads to deliver to JS layer
+
+ do {
+ if (!payload_handle) {
+ LoggerE("ERROR: trying to convert NULL payload handle to json");
+ break;
+ }
+
+ picojson::value parsed_payload;
+ {
+ char *payload_json_str = nullptr;
+ int error = conv_payload_internal_export_to_string(payload_handle, &payload_json_str);
+ if ((CONV_ERROR_NONE != error) || !payload_json_str) {
+ trace_conv_error(error, __LINE__, "converting payload handle to json");
+ break;
+ }
+
+ std::string err;
+ picojson::parse(parsed_payload, payload_json_str,
+ payload_json_str + strlen(payload_json_str), &err);
+ free(payload_json_str);
+ if (!err.empty()) {
+ LoggerE("Error parsing payload json: %s", err.c_str());
+ break;
+ }
+ }
+
+ if (!parsed_payload.is<picojson::object>()) {
+ LoggerE("ERROR: Payload is not an object");
+ break;
+ }
+
+ const picojson::object &payload_items = parsed_payload.get<picojson::object>();
+ for (auto it = std::begin(payload_items); it != std::end(payload_items); ++it) {
+ const std::string item_name = it->first;
+ const picojson::value item_value = it->second;
+
+ picojson::object payload_object;
+ payload_object[kKey] = picojson::value(item_name);
+
+ // Recognizing type of the payload
+ if (item_value.is<picojson::array>()) { // Byte array payload
+ payload_object[kPayloadDataType] = picojson::value(kTypeRawBytes);
+ payload_object[kValue] = item_value;
+ } else { // String payload
+ payload_object[kPayloadDataType] = picojson::value(kTypeString);
+ payload_object[kValue] = item_value;
+ }
+
+ payloads.push_back(picojson::value(payload_object));
+ }
+ } while(false);
+
+ return picojson::value(payloads);
+}
+
+std::string ConvergencePayloadArray::ExtractPayloadString(conv_payload_h payload, const char *key) {
+ ScopeLogger();
+ char *value = nullptr;
+ const int error = conv_payload_get_string(payload, key, &value);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_payload_get_string");
+ return "";
+ }
+
+ if (value) {
+ const std::string result = std::string(value);
+ free(value);
+ return result;
+ }
+ return "";
+}
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_PAYLOAD_H__
+#define CONVERGENCE_CONVERGENCE_PAYLOAD_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+
+/*enum ConvergencePayloadType {
+ kUnknownPayload = -1,
+ kStringPayload,
+ kRawBytesPayload
+};*/
+
+
+// TODO rename to simply Payload
+class ConvergencePayloadArray {
+ public:
+ ConvergencePayloadArray();
+ ConvergencePayloadArray(const picojson::value &payload_json);
+ virtual ~ConvergencePayloadArray();
+ ConvergencePayloadArray(const ConvergencePayloadArray&) = delete;
+ ConvergencePayloadArray(ConvergencePayloadArray&&) = delete;
+ ConvergencePayloadArray& operator=(const ConvergencePayloadArray&) = delete;
+ ConvergencePayloadArray& operator=(ConvergencePayloadArray&&) = delete;
+
+ public:
+ conv_payload_h GetHandle() const;
+ void FromJson(const picojson::value &payload_json);
+
+ public:
+ static picojson::value ToJson(conv_payload_h payload_handle);
+ static std::string ExtractPayloadString(conv_payload_h payload, const char *key);
+
+ private:
+ conv_payload_h payload_handle_;
+};
+
+/*
+class ConvergencePayload {
+ public:
+ ConvergencePayload();
+ virtual ~ConvergencePayload();
+ ConvergencePayload(const ConvergencePayload&) = delete;
+ ConvergencePayload(ConvergencePayload&&) = delete;
+ ConvergencePayload& operator=(const ConvergencePayload&) = delete;
+ ConvergencePayload& operator=(ConvergencePayload&&) = delete;
+
+ public:
+ void FromJson(const picojson::value &payload_json);
+
+ protected:
+ std::string id_;
+ ConvergencePayloadType type_;
+};
+
+class ConvergencePayloadString : public ConvergencePayload {
+ public:
+ ConvergencePayloadString();
+ virtual ~ConvergencePayloadString();
+ ConvergencePayloadString(const ConvergencePayloadString&) = delete;
+ ConvergencePayloadString(ConvergencePayloadString&&) = delete;
+ ConvergencePayloadString& operator=(const ConvergencePayloadString&) = delete;
+ ConvergencePayloadString& operator=(ConvergencePayloadString&&) = delete;
+
+ public:
+ void FromJson(const picojson::value &payload_json);
+
+ private:
+ std::string string_value_;
+};
+
+class ConvergencePayloadRawBytes : public ConvergencePayload {
+ public:
+ ConvergencePayloadRawBytes();
+ virtual ~ConvergencePayloadRawBytes();
+ ConvergencePayloadRawBytes(const ConvergencePayloadRawBytes&) = delete;
+ ConvergencePayloadRawBytes(ConvergencePayloadRawBytes&&) = delete;
+ ConvergencePayloadRawBytes& operator=(const ConvergencePayloadRawBytes&) = delete;
+ ConvergencePayloadRawBytes& operator=(ConvergencePayloadRawBytes&&) = delete;
+
+ public:
+ void FromJson(const picojson::value &payload_json);
+
+ private:
+ std::vector<unsigned char> raw_bytes_value_;
+};
+*/
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_PAYLOAD_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_remote_app_control_service.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_payload.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+using common::TizenResult;
+using common::TizenSuccess;
+
+namespace {
+// Payload data keys and some values
+static const std::string kPayload = "payload"; // ---
+
+// Service connection status keys
+static const std::string kServiceConnectionStatus = "connect_status"; // ---
+static const std::string kServiceConnectionStatusConnected = "service_connected";
+static const std::string kServiceConnectionStatusNotConnected = "service_not_connected";
+
+// Service listener status keys
+static const std::string kServiceListenerStatus = "listener_status"; //---
+static const std::string kServiceListenerStatusOk = "listener_ok"; // ---
+static const std::string kServiceListenerStatusError = "listener_error"; //---
+static const std::string kServiceListenerError = "listener_error"; //---
+} // namespace
+
+ConvergenceRemoteAppControlService::ConvergenceRemoteAppControlService()
+ : ConvergenceService()
+ , started_(false) {
+ ScopeLogger();
+}
+
+ConvergenceRemoteAppControlService::ConvergenceRemoteAppControlService(conv_device_h device, ConvergenceInstance *convergence_plugin)
+ : ConvergenceService(device, CONV_SERVICE_REMOTE_APP_CONTROL, convergence_plugin)
+ , started_(false) {
+ ScopeLogger();
+}
+
+ConvergenceRemoteAppControlService::~ConvergenceRemoteAppControlService() {
+ ScopeLogger();
+
+ // Release all memory, used by callback paramerers
+ for (size_t i = 0; i < callback_param_gc_.size(); i++) {
+ delete callback_param_gc_[i];
+ }
+ callback_param_gc_.clear();
+}
+
+void ConvergenceRemoteAppControlService::ServiceConnectedCb(conv_service_h service_handle,
+ conv_error_e error, conv_payload_h result, void* user_data) {
+ ScopeLogger();
+
+ CallbackParam *callbackParam = static_cast<CallbackParam *>(user_data);
+ if (!callbackParam) {
+ LoggerE("ERROR! NULL user data in Service Connect Callback");
+ return;
+ }
+
+ picojson::object param;
+ param["result_type"] = picojson::value("Connected");
+ //param[kPayload] = ConvergenceRemoteAppControlService::PayloadToJson(result);
+
+ if (CONV_ERROR_NONE == error) {
+ param[kServiceConnectionStatus] = picojson::value(kServiceConnectionStatusConnected);
+ callbackParam->plugin_->ReplyAsync(kRemoteAppControlListenerCallback,
+ callbackParam->callback_id_,
+ true,
+ param);
+ } else {
+ // Error occured during connection
+ param[kServiceConnectionStatus] = picojson::value(kServiceConnectionStatusNotConnected);
+ callbackParam->plugin_->ReplyAsync(kRemoteAppControlListenerCallback,
+ callbackParam->callback_id_,
+ false,
+ param);
+ }
+}
+
+common::TizenResult ConvergenceRemoteAppControlService::Connect(const int cur_listener_id) {
+ ScopeLogger();
+
+ conv_service_h service = FindServiceHandle();
+ if (!service) {
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+ // TODO: make a garbage collection and release this memory when service is disconnected
+ // and when whole manager is destructed
+ CallbackParam *param = new CallbackParam(convergence_plugin_, cur_listener_id);
+ callback_param_gc_.push_back(param);
+
+ const int error = conv_service_connect(service, ServiceConnectedCb, param);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_connect");
+ }
+
+ return TizenSuccess();
+}
+
+common::TizenResult ConvergenceRemoteAppControlService::Disconnect() {
+ ScopeLogger();
+
+ conv_service_h service = FindServiceHandle();
+ if (!service)
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+
+ const int error = conv_service_disconnect(service);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_disconnect");
+ }
+
+ return TizenSuccess();
+}
+
+void ConvergenceRemoteAppControlService::ServiceListenerCb(conv_service_h service_handle,
+ conv_channel_h channel_handle,
+ conv_error_e error, conv_payload_h result, void* user_data) {
+ ScopeLogger();
+
+ CallbackParam *callbackParam = static_cast<CallbackParam *>(user_data);
+ if (!callbackParam) {
+ LoggerE("ERROR! NULL user data in Service Listener Callback");
+ return;
+ }
+
+ picojson::object param;
+ param["payload"] = picojson::value("TODO");
+
+ // TODO parse the payload and fill the param
+
+ const std::string result_type = ConvergencePayloadArray::ExtractPayloadString(result, "result_type"); // TODO extract to constant kResultType = "result_type";
+ param["result_type"] = picojson::value(result_type);
+
+
+ if (CONV_ERROR_NONE == error) {
+ param[kServiceListenerStatus] = picojson::value(kServiceListenerStatusOk);
+ callbackParam->plugin_->ReplyAsync(kRemoteAppControlListenerCallback,
+ callbackParam->callback_id_,
+ true,
+ param);
+ } else {
+ // Error occured during connection
+ param[kServiceListenerStatus] = picojson::value(kServiceListenerStatusError);
+ param[kServiceListenerError] = picojson::value(static_cast<double>(error));
+ callbackParam->plugin_->ReplyAsync(kRemoteAppControlListenerCallback,
+ callbackParam->callback_id_,
+ false,
+ param);
+ }
+}
+
+void ConvergenceRemoteAppControlService::UpdateListener(const int cur_listener_id) {
+ ScopeLogger();
+ // TODO: make a garbage collection and release this memory when callback unset
+ // and when whole manager is destructed
+ CallbackParam *param = new CallbackParam(convergence_plugin_, cur_listener_id);
+ callback_param_gc_.push_back(param);
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return;
+ }
+ const int error = conv_service_set_listener_cb(service_handle, ServiceListenerCb, param);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_set_listener_cb");
+ } else {
+ LoggerI("Listener is set correctly");
+ }
+}
+
+void ConvergenceRemoteAppControlService::EnsureStarted() {
+ ScopeLogger();
+ if (started_)
+ return;
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return; // TODO handle error
+ }
+
+ const int error = conv_service_start(service_handle, nullptr, nullptr);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_publish START");
+ } else {
+ LoggerI("APP CONTROL SERVICE IS STARTED");
+ started_ = true;
+ }
+}
+
+common::TizenResult ConvergenceRemoteAppControlService::Launch(const char *appId, bool reply, const int cur_listener_id) {
+ ScopeLogger();
+
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return LogAndCreateTizenError(NotFoundError,
+ "Service with specified type does not exist");
+ }
+
+ // Create app control payload with passed appId
+ conv_payload_h payload = CreateAppIdPayload(appId, reply);
+ if (!payload) {
+ // Handle error
+ return TizenSuccess(); // TODO TizenError
+ }
+
+ // Update listener: assign it if it is not yet assigned
+ if (reply)
+ UpdateListener(cur_listener_id);
+
+ // Ensure the service was started
+ EnsureStarted();
+
+ // Sending app control on the remote device
+ const int error = conv_service_publish(service_handle, nullptr, payload);
+ if (CONV_ERROR_NONE != error) {
+ // TODO: Handle error
+ trace_conv_error(error, __LINE__, "conv_service_publish LAUNCH");
+ } else {
+ LoggerI("---- SEEMS APP CONTROL WAS LAUNCHED ----");
+ }
+
+/*
+ conv_service_start(service_handle, NULL, NULL);
+ conv_payload_h payload_handle;
+ conv_payload_create(&payload_handle);
+ app_control_h app_control = NULL;
+ app_control_create(&app_control);
+ app_control_set_app_id(app_control, "org.example.d2d_test");
+ app_control_set_operation(app_control, APP_CONTROL_OPERATION_MAIN);
+ conv_payload_set_app_control(payload_handle, "app_control", app_control);
+ conv_payload_set_string(payload_handle, "reply", "0");
+ conv_service_publish(service_handle, NULL, payload_handle);
+*/
+
+ conv_payload_destroy(payload);
+ return TizenSuccess();
+}
+
+conv_payload_h ConvergenceRemoteAppControlService::CreateAppIdPayload(const char *appId, bool reply) const {
+ ScopeLogger();
+
+ conv_payload_h payload = nullptr;
+ int error = conv_payload_create(&payload);
+ if (CONV_ERROR_NONE != error) {
+ // Handle error
+ }
+
+ app_control_h app_control = nullptr;
+ error = app_control_create(&app_control);
+ if (APP_CONTROL_ERROR_NONE != error) {
+ LoggerE("ERROR! AppControl API error [%d]", error);
+ }
+
+ error = app_control_set_app_id(app_control, appId);
+ if (APP_CONTROL_ERROR_NONE != error) {
+ LoggerE("ERROR! AppControl API error [%d]", error);
+ }
+
+ error = app_control_set_operation(app_control, APP_CONTROL_OPERATION_MAIN);
+ if (CONV_ERROR_NONE != error) {
+ // Handle error
+ }
+
+ error = conv_payload_set_app_control(payload, "app_control", app_control);
+ if (APP_CONTROL_ERROR_NONE != error) {
+ // Handle error
+ }
+
+ if (reply) {
+ error = conv_payload_set_string(payload, "reply", "1");
+ if (CONV_ERROR_NONE != error) {
+ // Handle error
+ }
+ }
+
+ return payload;
+}
+
+picojson::value ConvergenceRemoteAppControlService::PayloadToJson(conv_payload_h payload) {
+ ScopeLogger();
+ picojson::value payload_json;
+
+ // TODO convert payload to array of ApplicationControlData
+
+ return payload_json;
+}
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_REMOTE_APP_CONTROL_SERVICE_H__
+#define CONVERGENCE_CONVERGENCE_REMOTE_APP_CONTROL_SERVICE_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "convergence/convergence_service.h"
+#include "convergence/convergence_utils.h"
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceRemoteAppControlService : public ConvergenceService {
+
+ public:
+ ConvergenceRemoteAppControlService();
+ ConvergenceRemoteAppControlService(conv_device_h device, ConvergenceInstance *convergence_plugin);
+ virtual ~ConvergenceRemoteAppControlService();
+ ConvergenceRemoteAppControlService(const ConvergenceRemoteAppControlService&) = delete;
+ ConvergenceRemoteAppControlService(ConvergenceRemoteAppControlService&&) = delete;
+ ConvergenceRemoteAppControlService& operator=(const ConvergenceRemoteAppControlService&) = delete;
+ ConvergenceRemoteAppControlService& operator=(ConvergenceRemoteAppControlService&&) = delete;
+ public:
+ common::TizenResult Connect(const int cur_listener_id);
+ common::TizenResult Disconnect();
+ common::TizenResult Launch(const char *appId, bool reply, const int cur_listener_id);
+ private:
+ conv_payload_h CreateAppIdPayload(const char *appId, bool reply) const;
+ static picojson::value PayloadToJson(conv_payload_h payload);
+ void UpdateListener(const int cur_listener_id);
+ void EnsureStarted();
+ static void ServiceConnectedCb(conv_service_h service_handle,
+ conv_error_e error, conv_payload_h result, void* user_data);
+ static void ServiceListenerCb(conv_service_h service_handle,
+ conv_channel_h channel_handle,
+ conv_error_e error, conv_payload_h result, void* user_data);
+
+ private:
+ std::vector<CallbackParam *> callback_param_gc_;
+ bool started_;
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_REMOTE_APP_CONTROL_SERVICE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_service.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "convergence/convergence_utils.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+namespace {
+// Service keys
+static const std::string kServiceType = "serviceType";
+static const std::string kServiceConnectionState = "connectionState";
+static const std::string kId = "id";
+static const std::string kVersion = "version";
+} // namespace
+
+ConvergenceService::ConvergenceService()
+ : convergence_plugin_(nullptr)
+ , device_(nullptr)
+ , type_(CONV_SERVICE_NONE)
+ , service_handle_(nullptr) {
+ ScopeLogger();
+}
+
+ConvergenceService::ConvergenceService(conv_device_h device, conv_service_e type, ConvergenceInstance *convergence_plugin)
+ : convergence_plugin_(convergence_plugin)
+ , device_(device)
+ , type_(type)
+ , service_handle_(nullptr) {
+ ScopeLogger();
+}
+
+ConvergenceService::~ConvergenceService() {
+ ScopeLogger();
+ LoggerI("DESTROYING SERVICE HANDLE [0x0%x] in ConvergenceService destr", service_handle_);
+ conv_service_destroy(service_handle_);
+}
+
+struct ServiceSearchQuery {
+ conv_service_h handle;
+ conv_service_e type;
+};
+
+void ConvergenceService::ForEachServiceCb(conv_service_h service_handle, void* user_data) {
+ ScopeLogger();
+ ServiceSearchQuery *query = static_cast<ServiceSearchQuery *>(user_data);
+ if (!query)
+ return;
+ if (query->handle)
+ return; // Already found a required service handle (no need to analyze something else)
+
+ conv_service_e type = CONV_SERVICE_NONE;
+ int error = conv_service_get_type(service_handle, &type);
+ if (error != CONV_ERROR_NONE) {
+ // TODO Handle error
+ }
+
+ if (type != query->type) {
+ return;
+ }
+ conv_service_h clone = nullptr;
+ error = conv_service_clone(service_handle, &clone);
+ if (error != CONV_ERROR_NONE) {
+ // TODO Handle error
+ }
+ query->handle = clone;
+}
+
+conv_service_h ConvergenceService::FindServiceHandle() const {
+ ScopeLogger();
+ if (!service_handle_) {
+
+ if (!device_) {
+ LoggerE("ERROR: Device handle is NULL, can not get device services");
+ return nullptr;
+ }
+
+ ServiceSearchQuery query = {nullptr, type_};
+ const int error = conv_device_foreach_service(device_, ForEachServiceCb, &query);
+ if (CONV_ERROR_NONE != error) {
+ // TODO Handle error
+ trace_conv_error(error, __LINE__, "conv_device_foreach_service");
+ }
+ service_handle_ = query.handle;
+ }
+ return service_handle_;
+}
+
+std::string ConvergenceService::ExtractServicePropery(conv_service_h service_handle,
+ const char *property) {
+ ScopeLogger();
+ char *value = nullptr;
+ const int error = conv_service_get_property_string(service_handle, property, &value);
+ if (CONV_ERROR_NONE != error) {
+ trace_conv_error(error, __LINE__, "conv_service_get_property_string");
+ return "";
+ }
+
+ if (value) {
+ const std::string result = std::string(value);
+ free(value);
+ return result;
+ }
+ return "";
+}
+
+void ConvergenceService::Refresh() {
+ ScopeLogger();
+ conv_service_h service_handle = FindServiceHandle();
+ if (!service_handle) {
+ LoggerE("AAAAAA!!! Service not found");
+ return;
+ }
+
+ conv_service_connection_state_e state = CONV_SERVICE_CONNECTION_STATE_NONE;
+ const int error = conv_service_get_connection_state(service_handle, &state);
+ if (CONV_ERROR_NONE != error) {
+ LoggerE("ERROR! D2D API Get Service Connection State error [%d]", error);
+ trace_conv_error(error, __LINE__, "conv_service_get_connection_state");
+ } else {
+ connection_state_ = state;
+ }
+
+ id_ = ExtractServicePropery(service_handle, CONV_SERVICE_ID);
+ version_ = ExtractServicePropery(service_handle, CONV_SERVICE_VERSION);
+
+ LoggerE("Refreshed service id [%s] version [%s] connection state [%d]",
+ id_.c_str(), version_.c_str(), connection_state_);
+
+ //conv_service_destroy(service_handle);
+ //LoggerI("DESTROYING SERVICE HANDLE [0x0%x] in ConvergenceService Refresh", service_handle_);
+}
+
+picojson::value ConvergenceService::ToJson() const {
+ ScopeLogger();
+ picojson::object service_json;
+
+ service_json[kServiceType] = picojson::value(static_cast<double>(type_));
+ service_json[kServiceConnectionState] = picojson::value(static_cast<double>(connection_state_));
+
+ // Following fields are not used in Web API layer now, but I parse it for
+ // future extensions
+ service_json[kId] = picojson::value(id_);
+ service_json[kVersion] = picojson::value(version_);
+
+ return picojson::value(service_json);
+}
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_SERVICE_H__
+#define CONVERGENCE_CONVERGENCE_SERVICE_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceInstance;
+
+class ConvergenceService {
+
+ public:
+ ConvergenceService();
+ ConvergenceService(conv_device_h device, conv_service_e type, ConvergenceInstance *convergence_plugin);
+ virtual ~ConvergenceService();
+ ConvergenceService(const ConvergenceService&) = delete;
+ ConvergenceService(ConvergenceService&&) = delete;
+ ConvergenceService& operator=(const ConvergenceService&) = delete;
+ ConvergenceService& operator=(ConvergenceService&&) = delete;
+
+ public:
+ void Refresh();
+
+ public:
+ //conv_service_e get_type() const { return type_; }
+ //conv_device_h get_device() const {return device_; }
+ picojson::value ToJson() const;
+
+ protected:
+ conv_service_h FindServiceHandle() const;
+ static void ForEachServiceCb(conv_service_h service_handle, void* user_data);
+ std::string ExtractServicePropery(conv_service_h service_handle,
+ const char *property);
+
+ protected:
+ ConvergenceInstance *convergence_plugin_;
+
+ //private:
+ protected: // TODO switch back to private:
+ conv_device_h device_; // TODO rename to device_handle_
+ conv_service_e type_;
+ mutable conv_service_h service_handle_;
+ friend class ConvergenceAppCommunicationServerService; // It is needed to register the local service
+ private:
+ conv_service_connection_state_e connection_state_;
+ std::string id_;
+ std::string version_;
+};
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_SERVICE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO check includes
+#include "convergence/convergence_service.h"
+
+#include <glib.h>
+#include <d2d_conv_internal.h>
+
+#include "convergence/convergence_instance.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace convergence {
+
+
+
+
+void trace_conv_error(const int error, int line_number, const char *extra_text) {
+ std::string error_text;
+ switch (error) {
+ case CONV_ERROR_NONE:
+ error_text = "CONV_ERROR_NONE";
+ break;
+ case CONV_ERROR_INVALID_PARAMETER:
+ error_text = "CONV_ERROR_INVALID_PARAMETER";
+ break;
+ case CONV_ERROR_INVALID_OPERATION:
+ error_text = "CONV_ERROR_INVALID_OPERATION";
+ break;
+ case CONV_ERROR_OUT_OF_MEMORY:
+ error_text = "CONV_ERROR_OUT_OF_MEMORY";
+ break;
+ case CONV_ERROR_PERMISSION_DENIED:
+ error_text = "CONV_ERROR_PERMISSION_DENIED";
+ break;
+ case CONV_ERROR_NOT_SUPPORTED:
+ error_text = "CONV_ERROR_NOT_SUPPORTED";
+ break;
+ case CONV_ERROR_NO_DATA:
+ error_text = "CONV_ERROR_NO_DATA";
+ break;
+ default:
+ error_text = "UNSUPPORTED D2D ERROR CODE";
+ break;
+ }
+
+ if (extra_text) {
+ LoggerE("ERROR! D2D API error [%s], line %d: %s", error_text.c_str(), line_number, extra_text);
+ } else {
+ LoggerE("ERROR! D2D API error [%s], line %d", error_text.c_str(), line_number);
+ }
+}
+
+
+
+} // namespace convergence
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONVERGENCE_CONVERGENCE_UTILS_H__
+#define CONVERGENCE_CONVERGENCE_UTILS_H__
+
+// TODO check includes
+#include <d2d_conv_manager.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "common/tizen_result.h"
+
+namespace extension {
+namespace convergence {
+
+class ConvergenceInstance;
+
+struct CallbackParam {
+ CallbackParam(ConvergenceInstance *plg, int cbId)
+ : plugin_(plg), callback_id_(cbId) {}
+ ConvergenceInstance *plugin_;
+ int callback_id_;
+};
+
+
+void trace_conv_error(const int error, int line_number, const char *extra_text);
+
+} // namespace convergence
+} // namespace extension
+
+#endif // CONVERGENCE_CONVERGENCE_UTILS_H__
],
},
],
+ [
+ 'tizen_feature_convergence_support==1', {
+ 'dependencies': [
+ 'convergence/convergence.gyp:*',
+ ],
+ },
+ ],
], # end conditions
},
], # end targets