Merge lp:~abreu-alexandre/unity-webapps-qml/handle-bidirectional-callback-params into lp:unity-webapps-qml

Proposed by Alexandre Abreu
Status: Merged
Approved by: Robert Bruce Park
Approved revision: 129
Merged at revision: 127
Proposed branch: lp:~abreu-alexandre/unity-webapps-qml/handle-bidirectional-callback-params
Merge into: lp:unity-webapps-qml
Diff against target: 939 lines (+473/-56)
19 files modified
debian/rules (+1/-1)
debian/unity-webapps-qml-autopilot.install (+3/-3)
src/Ubuntu/UnityWebApps/Settings.qml (+1/-1)
src/Ubuntu/UnityWebApps/UnityWebApps.js (+38/-4)
src/Ubuntu/UnityWebApps/UnityWebApps.pro (+0/-3)
src/Ubuntu/UnityWebApps/UnityWebApps.qml (+50/-21)
src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js (+68/-0)
src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js (+63/-0)
tests/autopilot/autopilot.pro (+19/-1)
tests/autopilot/html/test_webapps_callback_dispatch.html (+57/-0)
tests/autopilot/html/test_webapps_callback_dispatch_api.js.in (+58/-0)
tests/autopilot/qml/FullWebViewApp.qml (+20/-1)
tests/autopilot/qml/test_webapps_callback_dispatch_api.qml (+14/-0)
tests/autopilot/unity_webapps_qml/tests/__init__.py (+9/-5)
tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py (+60/-0)
tests/integration/integration.pro (+0/-3)
tests/tests.pro (+1/-1)
tests/unit/test_qml/tst_dispatch.qml (+4/-4)
tools/qml-launcher/qml-launcher.cpp (+7/-8)
To merge this branch: bzr merge lp:~abreu-alexandre/unity-webapps-qml/handle-bidirectional-callback-params
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
WebApps Pending
Review via email: mp+226502@code.launchpad.net

Commit message

Add bidirectional callback support between js <-> qml,

Description of the change

Add bidirectional callback support between js <-> qml,

The current situation is that javascript can (and has to) handoff js callbacks to qml, so that events are properly propagated and translated. One use case recently came up that highlighted the limitation that basically the "callback translation between js & qml" does not work both ways. The use case is for content hub share handler that might ask js to call a qml callback when an operation is done.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
127. By Alexandre Abreu

handle bidirectional callback parameters betwee js & qml

Revision history for this message
Alberto Mardegan (mardy) wrote :

What is the use case?

I added a couple of inline comments.

128. By Alexandre Abreu

fixes

129. By Alexandre Abreu

fix nit

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/rules'
--- debian/rules 2013-07-11 17:53:01 +0000
+++ debian/rules 2014-07-18 17:03:51 +0000
@@ -9,7 +9,7 @@
99
10override_dh_install:10override_dh_install:
11 # install autopilot tests11 # install autopilot tests
12 cd tests/integration/autopilot; \12 cd tests/autopilot; \
13 set -ex; for python in $(shell pyversions -r); do \13 set -ex; for python in $(shell pyversions -r); do \
14 $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \14 $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \
15 done; \15 done; \
1616
=== modified file 'debian/unity-webapps-qml-autopilot.install'
--- debian/unity-webapps-qml-autopilot.install 2014-07-08 19:30:06 +0000
+++ debian/unity-webapps-qml-autopilot.install 2014-07-18 17:03:51 +0000
@@ -1,4 +1,4 @@
1tests/integration/autopilot/html/* usr/share/unity-webapps-qml/autopilot-tests/html/1tests/autopilot/html/* usr/share/unity-webapps-qml/autopilot-tests/html/
2tests/integration/autopilot/data/* usr/share/unity-webapps-qml/autopilot-tests/data/2tests/autopilot/data/* usr/share/unity-webapps-qml/autopilot-tests/data/
3tests/integration/autopilot/qml/* usr/share/unity-webapps-qml/autopilot-tests/qml/3tests/autopilot/qml/* usr/share/unity-webapps-qml/autopilot-tests/qml/
4usr/lib/python*4usr/lib/python*
55
=== modified file 'src/Ubuntu/UnityWebApps/Settings.qml'
--- src/Ubuntu/UnityWebApps/Settings.qml 2014-06-20 13:32:55 +0000
+++ src/Ubuntu/UnityWebApps/Settings.qml 2014-07-18 17:03:51 +0000
@@ -23,6 +23,6 @@
23 *23 *
24 */24 */
25 property bool injectExtraUbuntuApis: false25 property bool injectExtraUbuntuApis: false
26 property bool injectExtraUILaunchCapabilities: false26 property bool injectExtraContentShareCapabilities: false
27 property bool requiresInit: true27 property bool requiresInit: true
28}28}
2929
=== modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.js'
--- src/Ubuntu/UnityWebApps/UnityWebApps.js 2014-06-20 13:32:55 +0000
+++ src/Ubuntu/UnityWebApps/UnityWebApps.js 2014-07-18 17:03:51 +0000
@@ -36,12 +36,13 @@
36 * \param backends36 * \param backends
37 * \param userscriptContent37 * \param userscriptContent
38 */38 */
39 function _UnityWebApps(parentItem, bindeeProxies, accessPolicy) {39 function _UnityWebApps(parentItem, bindeeProxies, accessPolicy, injected_api_path) {
40 this._injected_unity_api_path = Qt.resolvedUrl('unity-webapps-api.js');40 this._injected_unity_api_path = injected_api_path;
41 this._bindeeProxies = bindeeProxies;41 this._bindeeProxies = bindeeProxies;
42 this._backends = null;42 this._backends = null;
43 this._userscripts = [];43 this._userscripts = [];
44 this._accessPolicy = accessPolicy;44 this._accessPolicy = accessPolicy;
45 this._callbackManager = UnityWebAppsUtils.makeCallbackManager();
4546
46 this._bind();47 this._bind();
47 };48 };
@@ -110,7 +111,7 @@
110 *111 *
111 */112 */
112 _onMessage: function(msg) {113 _onMessage: function(msg) {
113 if ( ! this._isValidWebAppsMessage(msg)) {114 if ( ! this._isValidWebAppsMessage(msg) && ! this._isValidCallbackMessage(msg)) {
114 this._log ('Invalid message received: ' + json.stringify(msg));115 this._log ('Invalid message received: ' + json.stringify(msg));
115116
116 return;117 return;
@@ -129,6 +130,7 @@
129 return true;130 return true;
130 },131 },
131132
133
132 /**134 /**
133 * \internal135 * \internal
134 *136 *
@@ -175,6 +177,23 @@
175 objectid: objectid,177 objectid: objectid,
176 class_name: class_name,178 class_name: class_name,
177 method_name: method_name}]);179 method_name: method_name}]);
180
181 } else if (target === UnityWebAppsUtils.UBUNTU_WEBAPPS_BINDING_API_CALLBACK_MESSAGE) {
182
183 var id = message.id;
184
185 if (! id || ! params)
186 return;
187
188 var cbfunc = this._callbackManager.get(id);
189 if (!cbfunc || !(cbfunc instanceof Function)) {
190 try {
191 console.log('Invalid callback id: ' + id);
192 }
193 catch (e) {}
194 return;
195 }
196 cbfunc.apply(null, params);
178 }197 }
179 },198 },
180199
@@ -215,6 +234,10 @@
215 return;234 return;
216235
217 var callback_args = Array.prototype.slice.call(arguments);236 var callback_args = Array.prototype.slice.call(arguments);
237 callback_args = callback_args.map (function (arg) {
238 return UnityWebAppsUtils.transformCallbacksToIds(arg, self._callbackManager);
239 });
240
218 var message = UnityWebAppsUtils.formatUnityWebappsCallbackCall(callbackid, callback_args);241 var message = UnityWebAppsUtils.formatUnityWebappsCallbackCall(callbackid, callback_args);
219242
220 self._bindeeProxies.sendToPage(JSON.stringify(message));243 self._bindeeProxies.sendToPage(JSON.stringify(message));
@@ -258,7 +281,7 @@
258 }281 }
259 }282 }
260 return ret;283 return ret;
261 },284 },
262285
263 /**286 /**
264 * \internal287 * \internal
@@ -281,6 +304,17 @@
281 message.target.indexOf('ubuntu-webapps-binding-call') === 0 &&304 message.target.indexOf('ubuntu-webapps-binding-call') === 0 &&
282 message.name &&305 message.name &&
283 message.args;306 message.args;
307 },
308
309 /**
310 * \internal
311 *
312 */
313 _isValidCallbackMessage: function(message) {
314 return message != null &&
315 message.target &&
316 message.target.indexOf('ubuntu-webapps-binding-callback-call') === 0 &&
317 message.args;
284 }318 }
285 };319 };
286320
287321
=== modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.pro'
--- src/Ubuntu/UnityWebApps/UnityWebApps.pro 2014-05-16 16:29:35 +0000
+++ src/Ubuntu/UnityWebApps/UnityWebApps.pro 2014-07-18 17:03:51 +0000
@@ -4,9 +4,6 @@
4TEMPLATE = subdirs4TEMPLATE = subdirs
5SUBDIRS += plugin5SUBDIRS += plugin
66
7#
8#
9#
10UNITY_API_JS_FILE = $$system($$PWD/../../../tools/inject-js-utils.py unity-webapps-api.js.in unity-webapps-api.js)7UNITY_API_JS_FILE = $$system($$PWD/../../../tools/inject-js-utils.py unity-webapps-api.js.in unity-webapps-api.js)
118
12inject_dependancies.target = unity-webapps-api.js9inject_dependancies.target = unity-webapps-api.js
1310
=== modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.qml'
--- src/Ubuntu/UnityWebApps/UnityWebApps.qml 2014-07-08 19:27:21 +0000
+++ src/Ubuntu/UnityWebApps/UnityWebApps.qml 2014-07-18 17:03:51 +0000
@@ -28,7 +28,6 @@
28import "./bindings/online-accounts/backend/online-accounts.js" as OnlineAccountsApiBackend28import "./bindings/online-accounts/backend/online-accounts.js" as OnlineAccountsApiBackend
29import "./bindings/download-manager/backend/download-api.js" as DownloadApiBackend29import "./bindings/download-manager/backend/download-api.js" as DownloadApiBackend
3030
31
32/*!31/*!
33 \qmltype UnityWebApps32 \qmltype UnityWebApps
34 \inqmlmodule Ubuntu.UnityWebApps 0.133 \inqmlmodule Ubuntu.UnityWebApps 0.1
@@ -121,10 +120,10 @@
121 property alias injectExtraUbuntuApis: settings.injectExtraUbuntuApis120 property alias injectExtraUbuntuApis: settings.injectExtraUbuntuApis
122121
123 /*!122 /*!
124 \qmlproperty bool UnityWebApps::injectExtraUILaunchCapabilities123 \qmlproperty bool UnityWebApps::injectExtraContentShareCapabilities
125124
126 */125 */
127 property alias injectExtraUILaunchCapabilities: settings.injectExtraUILaunchCapabilities126 property alias injectExtraContentShareCapabilities: settings.injectExtraContentShareCapabilities
128127
129 /*!128 /*!
130 \qmlproperty bool UnityWebApps::requiresInit129 \qmlproperty bool UnityWebApps::requiresInit
@@ -142,13 +141,22 @@
142 property var actionsContext: null141 property var actionsContext: null
143142
144 /*!143 /*!
145 \qmlproperty string UnityWebApps::_opt_backendProxies144 \qmlproperty string UnityWebApps::customBackendProxies
146145
147 Used only for testing.146 Used only for testing.
148 Allows optional (not the default ones) mocked backends to be used.147 Allows optional (not the default ones) mocked backends to be used.
149148
150 */149 */
151 property var _opt_backendProxies: null150 property var customBackendProxies: null
151
152 /*!
153 \qmlproperty string UnityWebApps::_opt_clientApiFileUrl
154
155 Used only for testing.
156 Allows optional (not the default ones) client api to be used instead of the default one.
157
158 */
159 property string customClientApiFileUrl: ""
152160
153 /*!161 /*!
154 \qmlproperty string UnityWebApps::_opt_homepage162 \qmlproperty string UnityWebApps::_opt_homepage
@@ -162,7 +170,7 @@
162170
163 Settings {171 Settings {
164 id: settings172 id: settings
165 injectExtraUILaunchCapabilities: name && name.length && name.length !== 0173 injectExtraContentShareCapabilities: name && name.length && name.length !== 0
166 }174 }
167175
168/*176/*
@@ -216,10 +224,15 @@
216 console.debug('__bind: ERROR bindee proxies not valid')224 console.debug('__bind: ERROR bindee proxies not valid')
217 return;225 return;
218 }226 }
227 var instance =
228 new UnityWebAppsJs.UnityWebApps(
229 webapps,
230 bindeeProxies,
231 __getPolicyForContent(settings),
232 customClientApiFileUrl && customClientApiFileUrl.length !== 0
233 ? customClientApiFileUrl
234 : Qt.resolvedUrl('unity-webapps-api.js'));
219235
220 var instance = new UnityWebAppsJs.UnityWebApps(webapps,
221 bindeeProxies,
222 __getPolicyForContent(settings));
223 internal.instance = instance;236 internal.instance = instance;
224237
225 if (internal.backends)238 if (internal.backends)
@@ -232,8 +245,8 @@
232 */245 */
233 function __createBackendsIfNeeded() {246 function __createBackendsIfNeeded() {
234 var backends;247 var backends;
235 if (_opt_backendProxies != null)248 if (customBackendProxies != null)
236 backends = _opt_backendProxies;249 backends = customBackendProxies;
237 else {250 else {
238 backends = __makeBackendProxies();251 backends = __makeBackendProxies();
239 }252 }
@@ -245,7 +258,7 @@
245258
246 */259 */
247 function __initBackends() {260 function __initBackends() {
248 if (__isValidWebAppName(webapps.name) || injectExtraUbuntuApis) {261 if (customBackendProxies || __isValidWebAppName(webapps.name) || injectExtraUbuntuApis) {
249 internal.backends = __createBackendsIfNeeded();262 internal.backends = __createBackendsIfNeeded();
250 if (internal.backends && internal.instance)263 if (internal.backends && internal.instance)
251 internal.instance.setBackends(internal.backends);264 internal.instance.setBackends(internal.backends);
@@ -368,6 +381,8 @@
368 }381 }
369 }382 }
370383
384 onCustomBackendProxiesChanged: __initBackends()
385
371 /*!386 /*!
372 \internal387 \internal
373388
@@ -448,17 +463,32 @@
448 this.restrictions = restrictions || BASIC_WEBAPPS_ALLOWED_APIS;463 this.restrictions = restrictions || BASIC_WEBAPPS_ALLOWED_APIS;
449 };464 };
450 RestrictedPolicy.prototype.allowed = function(signature) {465 RestrictedPolicy.prototype.allowed = function(signature) {
451 return this.restrictions.some(function(e) { return e === signature; });466 return this.restrictions.some(function(e) { return signature.match(e); });
467 };
468 RestrictedPolicy.prototype.add = function(signature) {
469 if (! this.restrictions.some(function(e) { return e === signature; })) {
470 this.restrictions.push(signature);
471 }
452 };472 };
453473
454 if (settings.injectExtraUbuntuApis)474 if (settings.injectExtraUbuntuApis)
455 return new PassthroughPolicy();475 return new PassthroughPolicy();
456476
457// if (settings.injectExtraUILaunchCapabilities)477 var policy = new RestrictedPolicy(['init',
458// return new RestrictedPolicy(["launchEmbeddedUI", "ContentHub.onShareRequested"]);478 'addAction',
459479 'clearAction',
460 // Inject only the basic init + api480 'clearActions',
461 return new PassthroughPolicy()481 'acceptData',
482 'Launcher.*',
483 'Notification.*',
484 'Launcher.*',
485 'MediaPlayer.*',
486 'MessagingIndicator.*']);
487 if (settings.injectExtraContentShareCapabilities) {
488 policy.add("launchEmbeddedUI");
489 policy.add("ContentHub.onShareRequested");
490 }
491 return policy;
462 }492 }
463493
464 /*!494 /*!
@@ -602,11 +632,10 @@
602 uiobject.destroy();632 uiobject.destroy();
603 return;633 return;
604 }634 }
605 function _onCompleted(data) {635 function _onCompleted(data, onResourceUploadedCallback) {
606 p.visible = true;636 p.visible = true;
607 uiobject.onCompleted.disconnect(_onCompleted);637 uiobject.onCompleted.disconnect(_onCompleted);
608 uiobject.destroy();638 callback(data, onResourceUploadedCallback);
609 callback(data);
610 }639 }
611 uiobject.onCompleted.connect(_onCompleted);640 uiobject.onCompleted.connect(_onCompleted);
612 };641 };
613642
=== modified file 'src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js'
--- src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js 2014-07-08 19:27:21 +0000
+++ src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js 2014-07-18 17:03:51 +0000
@@ -19,6 +19,7 @@
19.pragma library19.pragma library
2020
21var UBUNTU_WEBAPPS_BINDING_API_CALL_MESSAGE = "ubuntu-webapps-binding-call";21var UBUNTU_WEBAPPS_BINDING_API_CALL_MESSAGE = "ubuntu-webapps-binding-call";
22var UBUNTU_WEBAPPS_BINDING_API_CALLBACK_MESSAGE = "ubuntu-webapps-binding-callback-call";
22var UBUNTU_WEBAPPS_BINDING_OBJECT_METHOD_CALL_MESSAGE = "ubuntu-webapps-binding-call-object-method";23var UBUNTU_WEBAPPS_BINDING_OBJECT_METHOD_CALL_MESSAGE = "ubuntu-webapps-binding-call-object-method";
2324
2425
@@ -331,4 +332,71 @@
331 + pad(d.getUTCSeconds()) + 'Z';332 + pad(d.getUTCSeconds()) + 'Z';
332};333};
333334
335function transformFunctionToCallbackIdIfNecessary(obj, callbackManager) {
336 var ret = obj;
337 if (obj instanceof Function && callbackManager && callbackManager.store) {
338 var id = callbackManager.store(obj);
339 ret = {callbackid: id};
340 }
341 return ret;
342}
343
344function transformCallbacksToIds(obj, callbackManager) {
345 if ( ! isIterableObject(obj)) {
346 return transformFunctionToCallbackIdIfNecessary(obj, callbackManager);
347 }
348 var ret = (obj instanceof Array) ? [] : {};
349 for (var key in obj) {
350 if (obj.hasOwnProperty(key)) {
351 if (obj[key] instanceof Function) {
352 ret[key] = transformFunctionToCallbackIdIfNecessary(obj[key], callbackManager);
353 }
354 else if (isIterableObject (obj[key])) {
355 ret[key] = transformCallbacksToIds(obj[key]);
356 }
357 else {
358 ret[key] = obj[key];
359 }
360 }
361 }
362 return ret;
363}
364
365/**
366 * Wraps callback ids in proper callback that dispatch to the
367 * webpage thru a proper event
368 *
369 */
370function wrapCallbackIds(obj) {
371 if ( ! obj)
372 return obj;
373
374 if (!UnityWebAppsUtils.isIterableObject(obj)) {
375 return obj;
376 }
377
378 if (obj
379 && obj.hasOwnProperty('callbackid')
380 && obj.callbackid !== null) {
381 return this._makeWebpageCallback (obj.callbackid);
382 }
383
384 var ret = (obj instanceof Array) ? [] : {};
385 for (var key in obj) {
386 if (obj.hasOwnProperty(key)) {
387 if (UnityWebAppsUtils.isIterableObject (obj[key])) {
388 if (obj[key].callbackid !== null) {
389 ret[key] = this._makeWebpageCallback (obj[key].callbackid);
390 }
391 else {
392 ret[key] = this._wrapCallbackIds (obj[key]);
393 }
394 }
395 else {
396 ret[key] = obj[key];
397 }
398 }
399 }
400 return ret;
401}
334402
335403
=== modified file 'src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js'
--- src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js 2014-03-18 18:52:11 +0000
+++ src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js 2014-07-18 17:03:51 +0000
@@ -137,6 +137,64 @@
137 },137 },
138138
139 /**139 /**
140 * \internal
141 *
142 */
143 _makeWebpageCallback: function (callbackid) {
144 var self = this;
145 return function () {
146 var callback_args = Array.prototype.slice.call(arguments);
147
148 callback_args = callback_args.map (function (arg) {
149 return self._transformCallbacksToIds(arg);
150 });
151
152 var message = formatUnityWebappsCallbackCall(callbackid, JSON.stringify(callback_args));
153
154 self._sendToBackend(JSON.stringify(message));
155 };
156 },
157
158 /**
159 * \internal
160 *
161 * Wraps callback ids in proper callback that dispatch to the
162 * webpage thru a proper event
163 *
164 */
165 _wrapCallbackIds: function (obj) {
166 if ( ! obj)
167 return obj;
168 if ( ! isIterableObject(obj)) {
169 return obj;
170 }
171
172 if (obj
173 && obj.hasOwnProperty('callbackid')
174 && obj.callbackid !== null) {
175 return this._makeWebpageCallback (obj.callbackid);
176 }
177
178 var ret = (obj instanceof Array) ? [] : {};
179 for (var key in obj) {
180 if (obj.hasOwnProperty(key)) {
181 if (UnityWebAppsUtils.isIterableObject (obj[key])) {
182 if (obj[key].callbackid != null) {
183 ret[key] = this._makeWebpageCallback (obj[key].callbackid);
184 }
185 else {
186 ret[key] = this._wrapCallbackIds (obj[key]);
187 }
188 }
189 else {
190 ret[key] = obj[key];
191 }
192 }
193 }
194 return ret;
195 },
196
197 /**
140 * @internal198 * @internal
141 */199 */
142 _dispatchCallbackCall: function(id, args) {200 _dispatchCallbackCall: function(id, args) {
@@ -174,6 +232,11 @@
174 else if (arg instanceof Array) {232 else if (arg instanceof Array) {
175 return self._translateArgs(arg);233 return self._translateArgs(arg);
176 }234 }
235 else if (arg
236 && arg.hasOwnProperty('callbackid')
237 && arg.callbackid !== null) {
238 return self._makeWebpageCallback (arg.callbackid);
239 }
177240
178 return arg;241 return arg;
179 });242 });
180243
=== renamed directory 'tests/integration/autopilot' => 'tests/autopilot'
=== modified file 'tests/autopilot/autopilot.pro'
--- tests/integration/autopilot/autopilot.pro 2014-07-08 19:27:21 +0000
+++ tests/autopilot/autopilot.pro 2014-07-18 17:03:51 +0000
@@ -1,5 +1,16 @@
1TEMPLATE=aux1TEMPLATE=aux
22
3UNITY_API_JS_FILE = $$system($$PWD/../../tools/inject-js-utils.py ./html/test_webapps_callback_dispatch_api.js.in ./html/test_webapps_callback_dispatch_api.js)
4
5inject_dependancies.target = ./html/test_webapps_callback_dispatch_api.js
6inject_dependancies.depends = ./html/test_webapps_callback_dispatch_api.js.in
7inject_dependancies.commands = $$PWD/../../tools/inject-js-utils.py $< $@
8
9QMAKE_EXTRA_TARGETS += inject_dependancies
10
11PRE_TARGETDEPS += \
12 ./html/test_webapps_callback_dispatch_api.js
13
3OTHER_FILES += \14OTHER_FILES += \
4 $$system(ls ./qml/*) \15 $$system(ls ./qml/*) \
5 $$system(ls ./html/*) \16 $$system(ls ./html/*) \
@@ -11,4 +22,11 @@
11 unity_webapps_qml/tests/fake_servers.py \22 unity_webapps_qml/tests/fake_servers.py \
12 qml/WebviewBackendWebkit.qml \23 qml/WebviewBackendWebkit.qml \
13 qml/WebviewBackendOxide.qml \24 qml/WebviewBackendOxide.qml \
14 qml/message-server.js25 qml/message-server.js \
26 $$system(ls ./data/installed-webapps/*) \
27 unity_webapps_qml/tests/test_callbackDispatch.py \
28 html/test_webapps_callback_dispatch.html \
29 html/test_webapps_callback_dispatch_api.js \
30 html/test_webapps_callback_dispatch_api.js.in \
31 qml/test_webapps_callback_dispatch_api.qml
32
1533
=== added file 'tests/autopilot/html/test_webapps_callback_dispatch.html'
--- tests/autopilot/html/test_webapps_callback_dispatch.html 1970-01-01 00:00:00 +0000
+++ tests/autopilot/html/test_webapps_callback_dispatch.html 2014-07-18 17:03:51 +0000
@@ -0,0 +1,57 @@
1<html>
2
3<head>
4<title>Unity Webapps QML test: callback</title>
5
6<script>
7
8window.onload = function () {
9 var unity;
10 function init() {
11 unity = window.external.getUnityObject('1.0');
12 doCallbackLoop();
13 }
14
15 var CALLBACK_COUNT_MAX_COUNT = 10;
16 var callbackLoopCount = 0;
17 function doCallbackLoop(callback) {
18 if (callbackLoopCount >= CALLBACK_COUNT_MAX_COUNT) {
19 document.getElementById('content').innerHTML = 'callback-loop-count-reached';
20 return;
21 }
22 ++callbackLoopCount;
23
24 if (callback && typeof callback === 'Function') {
25 callback(doCallbackLoop);
26 }
27 else {
28 unity.withCallback(doCallbackLoop);
29 }
30 }
31
32 init();
33
34 if (window.external.getUnityObject) {
35 init();
36 }
37 else {
38 document.addEventListener('ubuntu-webapps-api-ready', function () {
39 init();
40 }, false);
41 }
42}
43
44</script>
45
46</head>
47
48<body>
49
50HELLO WORLD
51
52<div id="content">
53</div>
54
55</body>
56
57</html>
058
=== added file 'tests/autopilot/html/test_webapps_callback_dispatch_api.js.in'
--- tests/autopilot/html/test_webapps_callback_dispatch_api.js.in 1970-01-01 00:00:00 +0000
+++ tests/autopilot/html/test_webapps_callback_dispatch_api.js.in 2014-07-18 17:03:51 +0000
@@ -0,0 +1,58 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of unity-webapps-qml.
5 *
6 * unity-webapps-qml is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * unity-webapps-qml is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19(function () {
20
21 // Acknowledge that the API has been fully injected
22 var sendApiCreatedAcknowledgeEvent = function () {
23 var e = document.createEvent ("Events");
24 e.initEvent ("ubuntu-webapps-api-ready", false, false);
25 document.dispatchEvent (e);
26 };
27
28 //@include ../../src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js
29 //@include ../../src/Ubuntu/UnityWebApps/common/js/unity-backend-messaging-proxy.js
30 //@include ../../src/Ubuntu/UnityWebApps/common/js/unity-binding-proxy.js
31 //@include ../../src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js
32
33 var apiBuilder = function(backend) {
34 return {
35 withCallback: function(callback) {
36 backend.call('withCallback', [callback]);
37 }
38 };
39 };
40
41 var apiBridge = new UnityBindingBridge(
42 makeCallbackManager(),
43 createMessagingProxyForCurrentWebRuntime());
44
45 var api = apiBuilder (apiBridge);
46
47 apiBridge.setBindingApi(api);
48
49 if (!window.external)
50 window.external = {};
51
52 window.external.getUnityObject = function (version) {
53 return api;
54 };
55
56 sendApiCreatedAcknowledgeEvent();
57}) ();
58
059
=== modified file 'tests/autopilot/qml/FullWebViewApp.qml'
--- tests/integration/autopilot/qml/FullWebViewApp.qml 2014-07-08 19:27:21 +0000
+++ tests/autopilot/qml/FullWebViewApp.qml 2014-07-18 17:03:51 +0000
@@ -51,6 +51,10 @@
5151
52 property bool useOxide: false52 property bool useOxide: false
53 property string url: ""53 property string url: ""
54
55 property string apiBackendQmlFileUrl: ""
56 property string clientApiFileUrl: ""
57
54 property string webappName: ""58 property string webappName: ""
55 property string webappSearchPath: ""59 property string webappSearchPath: ""
56 property string webappHomepage: ""60 property string webappHomepage: ""
@@ -82,9 +86,18 @@
82 }86 }
8387
84 Loader {88 Loader {
89 id: apiBackendQmlFileLoader
90 source: apiBackendQmlFileUrl.length !== 0 ? apiBackendQmlFileUrl : ""
91 }
92
93 Loader {
85 id: unityWebappsComponentLoader94 id: unityWebappsComponentLoader
86 anchors.fill: parent95 anchors.fill: parent
87 sourceComponent: webView !== null && webappName.length !== 0 ? unityWebappsComponent : null96 sourceComponent: (webView !== null && webappName.length !== 0) ?
97 (apiBackendQmlFileUrl.length !== 0 ?
98 (apiBackendQmlFileLoader.item ? unityWebappsComponent : undefined)
99 : unityWebappsComponent)
100 : null
88 }101 }
89102
90 UnityWebappsAppModel {103 UnityWebappsAppModel {
@@ -100,9 +113,15 @@
100 objectName: "webappsContainer"113 objectName: "webappsContainer"
101 actionsContext: webappsActionsContext114 actionsContext: webappsActionsContext
102 name: root.webappName115 name: root.webappName
116 injectExtraUbuntuApis: true
117 customBackendProxies: apiBackendQmlFileLoader.item
118 ? apiBackendQmlFileLoader.item.buildapi()
119 : undefined
120 customClientApiFileUrl: root.clientApiFileUrl
103 bindee: webView121 bindee: webView
104 _opt_homepage: root.webappHomepage122 _opt_homepage: root.webappHomepage
105 model: webappModel123 model: webappModel
106 }124 }
107 }125 }
108}126}
127
109128
=== added file 'tests/autopilot/qml/test_webapps_callback_dispatch_api.qml'
--- tests/autopilot/qml/test_webapps_callback_dispatch_api.qml 1970-01-01 00:00:00 +0000
+++ tests/autopilot/qml/test_webapps_callback_dispatch_api.qml 2014-07-18 17:03:51 +0000
@@ -0,0 +1,14 @@
1import QtQuick 2.0
2
3Item {
4 function buildapi() {
5 return {
6 withCallback: function(clientCallback) {
7 function callbackLoop(callback) {
8 callback(callbackLoop);
9 }
10 clientCallback(callbackLoop);
11 }
12 };
13 }
14}
015
=== modified file 'tests/autopilot/unity_webapps_qml/tests/__init__.py'
--- tests/integration/autopilot/unity_webapps_qml/tests/__init__.py 2014-07-08 19:27:21 +0000
+++ tests/autopilot/unity_webapps_qml/tests/__init__.py 2014-07-18 17:03:51 +0000
@@ -21,7 +21,7 @@
2121
22from unity.tests import UnityTestCase22from unity.tests import UnityTestCase
2323
24LOCAL_QML_LAUNCHER_APP_PATH = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../../../../tools/qml-launcher/unity-webapps-qml-launcher')24LOCAL_QML_LAUNCHER_APP_PATH = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../../../tools/qml-launcher/unity-webapps-qml-launcher')
25INSTALLED_QML_LAUNCHER_APP_PATH = 'unity-webapps-qml-launcher'25INSTALLED_QML_LAUNCHER_APP_PATH = 'unity-webapps-qml-launcher'
2626
27# TODO create __init__.py.in27# TODO create __init__.py.in
@@ -31,6 +31,7 @@
31BASE_URL = ''31BASE_URL = ''
3232
33class UnityWebappsTestCaseBase(UnityTestCase):33class UnityWebappsTestCaseBase(UnityTestCase):
34
34 def setUp(self):35 def setUp(self):
35 super(UnityWebappsTestCaseBase, self).setUp()36 super(UnityWebappsTestCaseBase, self).setUp()
36 self.use_oxide = False37 self.use_oxide = False
@@ -56,7 +57,8 @@
56 webapp_name='unitywebappsqmllauncher',57 webapp_name='unitywebappsqmllauncher',
57 webapp_search_path="",58 webapp_search_path="",
58 webapp_homepage="",59 webapp_homepage="",
59 use_oxide=False):60 use_oxide=False,
61 extra_params=[]):
60 base_params = ['--qml=' + self.get_qml_browser_container_path(),62 base_params = ['--qml=' + self.get_qml_browser_container_path(),
61 '--app-id=' + webapp_name,63 '--app-id=' + webapp_name,
62 '--webappName=' + webapp_name,64 '--webappName=' + webapp_name,
@@ -74,15 +76,17 @@
74 if os.path.exists(LOCAL_QML_LAUNCHER_APP_PATH):76 if os.path.exists(LOCAL_QML_LAUNCHER_APP_PATH):
75 # we are local77 # we are local
76 base_params.append('--import=' + os.path.join (os.path.dirname(os.path.realpath(__file__)),78 base_params.append('--import=' + os.path.join (os.path.dirname(os.path.realpath(__file__)),
77 '../../../../../src'))79 '../../../../src'))
80
81 base_params += extra_params
7882
79 return base_params83 return base_params
8084
81 def launch_with_html_filepath(self, html_filepath):85 def launch_with_html_filepath(self, html_filepath, extra_params=[]):
82 self.assertThat(os.path.exists(html_filepath), Equals(True))86 self.assertThat(os.path.exists(html_filepath), Equals(True))
83 url = self.create_file_url(html_filepath)87 url = self.create_file_url(html_filepath)
8488
85 self.launch_application(self.get_launch_params(url))89 self.launch_application(self.get_launch_params(url, 'unitywebappsqmllauncher', '', '', False, extra_params))
86 self.assert_url_eventually_loaded(url)90 self.assert_url_eventually_loaded(url)
8791
88 def launch_application(self, args):92 def launch_application(self, args):
8993
=== added file 'tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py'
--- tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py 2014-07-18 17:03:51 +0000
@@ -0,0 +1,60 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2014 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8from __future__ import absolute_import
9
10import time
11import os
12
13from testtools.matchers import Equals, GreaterThan, NotEquals
14from autopilot.matchers import Eventually
15
16from unity_webapps_qml.tests import UnityWebappsTestCaseBase
17
18LOCAL_HTML_TEST_FILE = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../html/test_webapps_callback_dispatch.html')
19INSTALLED_HTML_TEST_FILE = '/usr/share/unity-webapps-qml/autopilot-tests/html/test_webapps_callback_dispatch.html'
20
21LOCAL_JS_TEST_FILE = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../html/test_webapps_callback_dispatch_api.js')
22INSTALLED_JS_TEST_FILE = '/usr/share/unity-webapps-qml/autopilot-tests/html/test_webapps_callback_dispatch_api.js'
23
24LOCAL_QML_BACKEND_TEST_FILE = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../qml/test_webapps_callback_dispatch_api.qml')
25INSTALLED_QML_BACKEND_TEST_FILE = '/usr/share/unity-webapps-qml/autopilot-tests/qml/test_webapps_callback_dispatch_api.qml'
26
27class WebappsCallbackDispatchTestCaseBase(UnityWebappsTestCaseBase):
28 def setUp(self):
29 super(WebappsCallbackDispatchTestCaseBase, self).setUp()
30 self.launch_with_html_filepath(
31 self.get_html_test_file(),
32 ['--clientApiFileUrl=file://' + self.get_js_test_file(),
33 '--apiBackendQmlFileUrl=file://' + self.get_qml_test_file()])
34
35 def get_html_test_file(self):
36 if os.path.exists(LOCAL_HTML_TEST_FILE):
37 return os.path.abspath(LOCAL_HTML_TEST_FILE)
38 return INSTALLED_HTML_TEST_FILE
39
40 def get_js_test_file(self):
41 if os.path.exists(LOCAL_JS_TEST_FILE):
42 return os.path.abspath(LOCAL_JS_TEST_FILE)
43 return INSTALLED_JS_TEST_FILE
44
45 def get_qml_test_file(self):
46 print LOCAL_QML_BACKEND_TEST_FILE
47 if os.path.exists(LOCAL_QML_BACKEND_TEST_FILE):
48 return os.path.abspath(LOCAL_QML_BACKEND_TEST_FILE)
49 return INSTALLED_QML_BACKEND_TEST_FILE
50
51 def test_bidirectionalCallback(self):
52 self.assertThat(
53 lambda: self.eval_expression_in_page_unsafe(
54 'return window.external.getUnityObject("1.0") != null;'),
55 Eventually(Equals(True)))
56
57 self.assertThat(
58 lambda: self.eval_expression_in_page_unsafe("return document.getElementById('content').innerHTML;"),
59 Eventually(Equals('callback-loop-count-reached')))
60
061
=== removed directory 'tests/integration'
=== removed file 'tests/integration/integration.pro'
--- tests/integration/integration.pro 2013-07-09 19:02:23 +0000
+++ tests/integration/integration.pro 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1TEMPLATE = subdirs
2
3SUBDIRS = autopilot
40
=== modified file 'tests/tests.pro'
--- tests/tests.pro 2013-07-24 20:31:38 +0000
+++ tests/tests.pro 2014-07-18 17:03:51 +0000
@@ -1,4 +1,4 @@
1TEMPLATE=subdirs1TEMPLATE=subdirs
22
3SUBDIRS = unit integration3SUBDIRS = unit autopilot
44
55
=== modified file 'tests/unit/test_qml/tst_dispatch.qml'
--- tests/unit/test_qml/tst_dispatch.qml 2014-04-14 20:57:17 +0000
+++ tests/unit/test_qml/tst_dispatch.qml 2014-07-18 17:03:51 +0000
@@ -19,7 +19,7 @@
1919
20 var simple_backend = {This: { Is: { A: {Backend: function (args) { mockedWebView.called(args) } } } } };20 var simple_backend = {This: { Is: { A: {Backend: function (args) { mockedWebView.called(args) } } } } };
2121
22 webapps._opt_backendProxies = simple_backend;22 webapps.customBackendProxies = simple_backend;
23 webapps.name = "test_properBackendDispatched";23 webapps.name = "test_properBackendDispatched";
24 webapps.bindee = mockedWebView;24 webapps.bindee = mockedWebView;
2525
@@ -47,7 +47,7 @@
4747
48 var simple_backend = {This: { Is: { A: {Backend: action } } } };48 var simple_backend = {This: { Is: { A: {Backend: action } } } };
4949
50 webapps._opt_backendProxies = simple_backend;50 webapps.customBackendProxies = simple_backend;
51 webapps.name = "test_backendDispatchedWithProperArguments";51 webapps.name = "test_backendDispatchedWithProperArguments";
52 webapps.bindee = mockedWebView;52 webapps.bindee = mockedWebView;
5353
@@ -65,7 +65,7 @@
6565
66 var invalid_backend = {This: { Is: { Not: { A: {Backend: function (args) { mockedWebView.called(args) } } } } } };66 var invalid_backend = {This: { Is: { Not: { A: {Backend: function (args) { mockedWebView.called(args) } } } } } };
6767
68 webapps._opt_backendProxies = invalid_backend;68 webapps.customBackendProxies = invalid_backend;
69 webapps.name = "test_invalidBackendNotDispatched";69 webapps.name = "test_invalidBackendNotDispatched";
70 webapps.bindee = mockedWebView;70 webapps.bindee = mockedWebView;
7171
@@ -94,7 +94,7 @@
9494
95 var backend = {This: { Is: { A: {Backend: action } } } };95 var backend = {This: { Is: { A: {Backend: action } } } };
9696
97 webapps._opt_backendProxies = backend;97 webapps.customBackendProxies = backend;
98 webapps.name = "test_callbacksAreWrapped";98 webapps.name = "test_callbacksAreWrapped";
99 webapps.bindee = mockedWebView;99 webapps.bindee = mockedWebView;
100100
101101
=== modified file 'tools/qml-launcher/qml-launcher.cpp'
--- tools/qml-launcher/qml-launcher.cpp 2014-07-08 19:27:21 +0000
+++ tools/qml-launcher/qml-launcher.cpp 2014-07-18 17:03:51 +0000
@@ -119,17 +119,17 @@
119119
120 QString value = argument.right(argument.count() - argument.indexOf(VALUE_HEADER) - 1);120 QString value = argument.right(argument.count() - argument.indexOf(VALUE_HEADER) - 1);
121121
122 qDebug() << "Adding property: "122 qDebug() << "Adding property:"
123 << property123 << property
124 << ", "124 << ","
125 << "value: "125 << "value:"
126 << value;126 << value;
127127
128 properties.insert(property, value);128 properties.insert(property, value);
129 }129 }
130 else130 else
131 {131 {
132 qDebug() << "Ignoring argument: " << argument;132 qDebug() << "Ignoring argument:" << argument;
133 }133 }
134 }134 }
135135
@@ -147,13 +147,13 @@
147 QFileInfo f(qmlfile);147 QFileInfo f(qmlfile);
148 if (!f.exists() || !f.isFile())148 if (!f.exists() || !f.isFile())
149 {149 {
150 qDebug() << "QML file not found or not a file: " << qmlfile;150 qDebug() << "QML file not found or not a file:" << qmlfile;
151 return EXIT_FAILURE;151 return EXIT_FAILURE;
152 }152 }
153153
154 if ( ! importPath.isEmpty())154 if ( ! importPath.isEmpty())
155 {155 {
156 qDebug() << "Setting import path to: " << importPath;156 qDebug() << "Setting import path to:" << importPath;
157 qputenv("QML2_IMPORT_PATH", importPath.toLatin1());157 qputenv("QML2_IMPORT_PATH", importPath.toLatin1());
158 }158 }
159159
@@ -167,7 +167,7 @@
167167
168 if ( ! inspector.isEmpty())168 if ( ! inspector.isEmpty())
169 {169 {
170 qDebug() << "Inspector server being set to: " << inspector;170 qDebug() << "Inspector server being set to:" << inspector;
171171
172 qputenv("QTWEBKIT_INSPECTOR_SERVER", inspector.toLatin1());172 qputenv("QTWEBKIT_INSPECTOR_SERVER", inspector.toLatin1());
173 }173 }
@@ -202,7 +202,6 @@
202 if (useOxide) {202 if (useOxide) {
203 object->setProperty("useOxide", true);203 object->setProperty("useOxide", true);
204 }204 }
205
206 component.completeCreate();205 component.completeCreate();
207206
208 if (window)207 if (window)

Subscribers

People subscribed via source and target branches

to all changes: