Merge lp:~abreu-alexandre/unity-webapps-qml/handle-bidirectional-callback-params into lp:unity-webapps-qml
- handle-bidirectional-callback-params
- Merge into trunk
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 |
Related bugs: |
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:135
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 127. By Alexandre Abreu
-
handle bidirectional callback parameters betwee js & qml
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
1 | === modified file 'debian/rules' |
2 | --- debian/rules 2013-07-11 17:53:01 +0000 |
3 | +++ debian/rules 2014-07-18 17:03:51 +0000 |
4 | @@ -9,7 +9,7 @@ |
5 | |
6 | override_dh_install: |
7 | # install autopilot tests |
8 | - cd tests/integration/autopilot; \ |
9 | + cd tests/autopilot; \ |
10 | set -ex; for python in $(shell pyversions -r); do \ |
11 | $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \ |
12 | done; \ |
13 | |
14 | === modified file 'debian/unity-webapps-qml-autopilot.install' |
15 | --- debian/unity-webapps-qml-autopilot.install 2014-07-08 19:30:06 +0000 |
16 | +++ debian/unity-webapps-qml-autopilot.install 2014-07-18 17:03:51 +0000 |
17 | @@ -1,4 +1,4 @@ |
18 | -tests/integration/autopilot/html/* usr/share/unity-webapps-qml/autopilot-tests/html/ |
19 | -tests/integration/autopilot/data/* usr/share/unity-webapps-qml/autopilot-tests/data/ |
20 | -tests/integration/autopilot/qml/* usr/share/unity-webapps-qml/autopilot-tests/qml/ |
21 | +tests/autopilot/html/* usr/share/unity-webapps-qml/autopilot-tests/html/ |
22 | +tests/autopilot/data/* usr/share/unity-webapps-qml/autopilot-tests/data/ |
23 | +tests/autopilot/qml/* usr/share/unity-webapps-qml/autopilot-tests/qml/ |
24 | usr/lib/python* |
25 | |
26 | === modified file 'src/Ubuntu/UnityWebApps/Settings.qml' |
27 | --- src/Ubuntu/UnityWebApps/Settings.qml 2014-06-20 13:32:55 +0000 |
28 | +++ src/Ubuntu/UnityWebApps/Settings.qml 2014-07-18 17:03:51 +0000 |
29 | @@ -23,6 +23,6 @@ |
30 | * |
31 | */ |
32 | property bool injectExtraUbuntuApis: false |
33 | - property bool injectExtraUILaunchCapabilities: false |
34 | + property bool injectExtraContentShareCapabilities: false |
35 | property bool requiresInit: true |
36 | } |
37 | |
38 | === modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.js' |
39 | --- src/Ubuntu/UnityWebApps/UnityWebApps.js 2014-06-20 13:32:55 +0000 |
40 | +++ src/Ubuntu/UnityWebApps/UnityWebApps.js 2014-07-18 17:03:51 +0000 |
41 | @@ -36,12 +36,13 @@ |
42 | * \param backends |
43 | * \param userscriptContent |
44 | */ |
45 | - function _UnityWebApps(parentItem, bindeeProxies, accessPolicy) { |
46 | - this._injected_unity_api_path = Qt.resolvedUrl('unity-webapps-api.js'); |
47 | + function _UnityWebApps(parentItem, bindeeProxies, accessPolicy, injected_api_path) { |
48 | + this._injected_unity_api_path = injected_api_path; |
49 | this._bindeeProxies = bindeeProxies; |
50 | this._backends = null; |
51 | this._userscripts = []; |
52 | this._accessPolicy = accessPolicy; |
53 | + this._callbackManager = UnityWebAppsUtils.makeCallbackManager(); |
54 | |
55 | this._bind(); |
56 | }; |
57 | @@ -110,7 +111,7 @@ |
58 | * |
59 | */ |
60 | _onMessage: function(msg) { |
61 | - if ( ! this._isValidWebAppsMessage(msg)) { |
62 | + if ( ! this._isValidWebAppsMessage(msg) && ! this._isValidCallbackMessage(msg)) { |
63 | this._log ('Invalid message received: ' + json.stringify(msg)); |
64 | |
65 | return; |
66 | @@ -129,6 +130,7 @@ |
67 | return true; |
68 | }, |
69 | |
70 | + |
71 | /** |
72 | * \internal |
73 | * |
74 | @@ -175,6 +177,23 @@ |
75 | objectid: objectid, |
76 | class_name: class_name, |
77 | method_name: method_name}]); |
78 | + |
79 | + } else if (target === UnityWebAppsUtils.UBUNTU_WEBAPPS_BINDING_API_CALLBACK_MESSAGE) { |
80 | + |
81 | + var id = message.id; |
82 | + |
83 | + if (! id || ! params) |
84 | + return; |
85 | + |
86 | + var cbfunc = this._callbackManager.get(id); |
87 | + if (!cbfunc || !(cbfunc instanceof Function)) { |
88 | + try { |
89 | + console.log('Invalid callback id: ' + id); |
90 | + } |
91 | + catch (e) {} |
92 | + return; |
93 | + } |
94 | + cbfunc.apply(null, params); |
95 | } |
96 | }, |
97 | |
98 | @@ -215,6 +234,10 @@ |
99 | return; |
100 | |
101 | var callback_args = Array.prototype.slice.call(arguments); |
102 | + callback_args = callback_args.map (function (arg) { |
103 | + return UnityWebAppsUtils.transformCallbacksToIds(arg, self._callbackManager); |
104 | + }); |
105 | + |
106 | var message = UnityWebAppsUtils.formatUnityWebappsCallbackCall(callbackid, callback_args); |
107 | |
108 | self._bindeeProxies.sendToPage(JSON.stringify(message)); |
109 | @@ -258,7 +281,7 @@ |
110 | } |
111 | } |
112 | return ret; |
113 | - }, |
114 | + }, |
115 | |
116 | /** |
117 | * \internal |
118 | @@ -281,6 +304,17 @@ |
119 | message.target.indexOf('ubuntu-webapps-binding-call') === 0 && |
120 | message.name && |
121 | message.args; |
122 | + }, |
123 | + |
124 | + /** |
125 | + * \internal |
126 | + * |
127 | + */ |
128 | + _isValidCallbackMessage: function(message) { |
129 | + return message != null && |
130 | + message.target && |
131 | + message.target.indexOf('ubuntu-webapps-binding-callback-call') === 0 && |
132 | + message.args; |
133 | } |
134 | }; |
135 | |
136 | |
137 | === modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.pro' |
138 | --- src/Ubuntu/UnityWebApps/UnityWebApps.pro 2014-05-16 16:29:35 +0000 |
139 | +++ src/Ubuntu/UnityWebApps/UnityWebApps.pro 2014-07-18 17:03:51 +0000 |
140 | @@ -4,9 +4,6 @@ |
141 | TEMPLATE = subdirs |
142 | SUBDIRS += plugin |
143 | |
144 | -# |
145 | -# |
146 | -# |
147 | UNITY_API_JS_FILE = $$system($$PWD/../../../tools/inject-js-utils.py unity-webapps-api.js.in unity-webapps-api.js) |
148 | |
149 | inject_dependancies.target = unity-webapps-api.js |
150 | |
151 | === modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.qml' |
152 | --- src/Ubuntu/UnityWebApps/UnityWebApps.qml 2014-07-08 19:27:21 +0000 |
153 | +++ src/Ubuntu/UnityWebApps/UnityWebApps.qml 2014-07-18 17:03:51 +0000 |
154 | @@ -28,7 +28,6 @@ |
155 | import "./bindings/online-accounts/backend/online-accounts.js" as OnlineAccountsApiBackend |
156 | import "./bindings/download-manager/backend/download-api.js" as DownloadApiBackend |
157 | |
158 | - |
159 | /*! |
160 | \qmltype UnityWebApps |
161 | \inqmlmodule Ubuntu.UnityWebApps 0.1 |
162 | @@ -121,10 +120,10 @@ |
163 | property alias injectExtraUbuntuApis: settings.injectExtraUbuntuApis |
164 | |
165 | /*! |
166 | - \qmlproperty bool UnityWebApps::injectExtraUILaunchCapabilities |
167 | + \qmlproperty bool UnityWebApps::injectExtraContentShareCapabilities |
168 | |
169 | */ |
170 | - property alias injectExtraUILaunchCapabilities: settings.injectExtraUILaunchCapabilities |
171 | + property alias injectExtraContentShareCapabilities: settings.injectExtraContentShareCapabilities |
172 | |
173 | /*! |
174 | \qmlproperty bool UnityWebApps::requiresInit |
175 | @@ -142,13 +141,22 @@ |
176 | property var actionsContext: null |
177 | |
178 | /*! |
179 | - \qmlproperty string UnityWebApps::_opt_backendProxies |
180 | + \qmlproperty string UnityWebApps::customBackendProxies |
181 | |
182 | Used only for testing. |
183 | Allows optional (not the default ones) mocked backends to be used. |
184 | |
185 | */ |
186 | - property var _opt_backendProxies: null |
187 | + property var customBackendProxies: null |
188 | + |
189 | + /*! |
190 | + \qmlproperty string UnityWebApps::_opt_clientApiFileUrl |
191 | + |
192 | + Used only for testing. |
193 | + Allows optional (not the default ones) client api to be used instead of the default one. |
194 | + |
195 | + */ |
196 | + property string customClientApiFileUrl: "" |
197 | |
198 | /*! |
199 | \qmlproperty string UnityWebApps::_opt_homepage |
200 | @@ -162,7 +170,7 @@ |
201 | |
202 | Settings { |
203 | id: settings |
204 | - injectExtraUILaunchCapabilities: name && name.length && name.length !== 0 |
205 | + injectExtraContentShareCapabilities: name && name.length && name.length !== 0 |
206 | } |
207 | |
208 | /* |
209 | @@ -216,10 +224,15 @@ |
210 | console.debug('__bind: ERROR bindee proxies not valid') |
211 | return; |
212 | } |
213 | + var instance = |
214 | + new UnityWebAppsJs.UnityWebApps( |
215 | + webapps, |
216 | + bindeeProxies, |
217 | + __getPolicyForContent(settings), |
218 | + customClientApiFileUrl && customClientApiFileUrl.length !== 0 |
219 | + ? customClientApiFileUrl |
220 | + : Qt.resolvedUrl('unity-webapps-api.js')); |
221 | |
222 | - var instance = new UnityWebAppsJs.UnityWebApps(webapps, |
223 | - bindeeProxies, |
224 | - __getPolicyForContent(settings)); |
225 | internal.instance = instance; |
226 | |
227 | if (internal.backends) |
228 | @@ -232,8 +245,8 @@ |
229 | */ |
230 | function __createBackendsIfNeeded() { |
231 | var backends; |
232 | - if (_opt_backendProxies != null) |
233 | - backends = _opt_backendProxies; |
234 | + if (customBackendProxies != null) |
235 | + backends = customBackendProxies; |
236 | else { |
237 | backends = __makeBackendProxies(); |
238 | } |
239 | @@ -245,7 +258,7 @@ |
240 | |
241 | */ |
242 | function __initBackends() { |
243 | - if (__isValidWebAppName(webapps.name) || injectExtraUbuntuApis) { |
244 | + if (customBackendProxies || __isValidWebAppName(webapps.name) || injectExtraUbuntuApis) { |
245 | internal.backends = __createBackendsIfNeeded(); |
246 | if (internal.backends && internal.instance) |
247 | internal.instance.setBackends(internal.backends); |
248 | @@ -368,6 +381,8 @@ |
249 | } |
250 | } |
251 | |
252 | + onCustomBackendProxiesChanged: __initBackends() |
253 | + |
254 | /*! |
255 | \internal |
256 | |
257 | @@ -448,17 +463,32 @@ |
258 | this.restrictions = restrictions || BASIC_WEBAPPS_ALLOWED_APIS; |
259 | }; |
260 | RestrictedPolicy.prototype.allowed = function(signature) { |
261 | - return this.restrictions.some(function(e) { return e === signature; }); |
262 | + return this.restrictions.some(function(e) { return signature.match(e); }); |
263 | + }; |
264 | + RestrictedPolicy.prototype.add = function(signature) { |
265 | + if (! this.restrictions.some(function(e) { return e === signature; })) { |
266 | + this.restrictions.push(signature); |
267 | + } |
268 | }; |
269 | |
270 | if (settings.injectExtraUbuntuApis) |
271 | return new PassthroughPolicy(); |
272 | |
273 | -// if (settings.injectExtraUILaunchCapabilities) |
274 | -// return new RestrictedPolicy(["launchEmbeddedUI", "ContentHub.onShareRequested"]); |
275 | - |
276 | - // Inject only the basic init + api |
277 | - return new PassthroughPolicy() |
278 | + var policy = new RestrictedPolicy(['init', |
279 | + 'addAction', |
280 | + 'clearAction', |
281 | + 'clearActions', |
282 | + 'acceptData', |
283 | + 'Launcher.*', |
284 | + 'Notification.*', |
285 | + 'Launcher.*', |
286 | + 'MediaPlayer.*', |
287 | + 'MessagingIndicator.*']); |
288 | + if (settings.injectExtraContentShareCapabilities) { |
289 | + policy.add("launchEmbeddedUI"); |
290 | + policy.add("ContentHub.onShareRequested"); |
291 | + } |
292 | + return policy; |
293 | } |
294 | |
295 | /*! |
296 | @@ -602,11 +632,10 @@ |
297 | uiobject.destroy(); |
298 | return; |
299 | } |
300 | - function _onCompleted(data) { |
301 | + function _onCompleted(data, onResourceUploadedCallback) { |
302 | p.visible = true; |
303 | uiobject.onCompleted.disconnect(_onCompleted); |
304 | - uiobject.destroy(); |
305 | - callback(data); |
306 | + callback(data, onResourceUploadedCallback); |
307 | } |
308 | uiobject.onCompleted.connect(_onCompleted); |
309 | }; |
310 | |
311 | === modified file 'src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js' |
312 | --- src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js 2014-07-08 19:27:21 +0000 |
313 | +++ src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js 2014-07-18 17:03:51 +0000 |
314 | @@ -19,6 +19,7 @@ |
315 | .pragma library |
316 | |
317 | var UBUNTU_WEBAPPS_BINDING_API_CALL_MESSAGE = "ubuntu-webapps-binding-call"; |
318 | +var UBUNTU_WEBAPPS_BINDING_API_CALLBACK_MESSAGE = "ubuntu-webapps-binding-callback-call"; |
319 | var UBUNTU_WEBAPPS_BINDING_OBJECT_METHOD_CALL_MESSAGE = "ubuntu-webapps-binding-call-object-method"; |
320 | |
321 | |
322 | @@ -331,4 +332,71 @@ |
323 | + pad(d.getUTCSeconds()) + 'Z'; |
324 | }; |
325 | |
326 | +function transformFunctionToCallbackIdIfNecessary(obj, callbackManager) { |
327 | + var ret = obj; |
328 | + if (obj instanceof Function && callbackManager && callbackManager.store) { |
329 | + var id = callbackManager.store(obj); |
330 | + ret = {callbackid: id}; |
331 | + } |
332 | + return ret; |
333 | +} |
334 | + |
335 | +function transformCallbacksToIds(obj, callbackManager) { |
336 | + if ( ! isIterableObject(obj)) { |
337 | + return transformFunctionToCallbackIdIfNecessary(obj, callbackManager); |
338 | + } |
339 | + var ret = (obj instanceof Array) ? [] : {}; |
340 | + for (var key in obj) { |
341 | + if (obj.hasOwnProperty(key)) { |
342 | + if (obj[key] instanceof Function) { |
343 | + ret[key] = transformFunctionToCallbackIdIfNecessary(obj[key], callbackManager); |
344 | + } |
345 | + else if (isIterableObject (obj[key])) { |
346 | + ret[key] = transformCallbacksToIds(obj[key]); |
347 | + } |
348 | + else { |
349 | + ret[key] = obj[key]; |
350 | + } |
351 | + } |
352 | + } |
353 | + return ret; |
354 | +} |
355 | + |
356 | +/** |
357 | + * Wraps callback ids in proper callback that dispatch to the |
358 | + * webpage thru a proper event |
359 | + * |
360 | + */ |
361 | +function wrapCallbackIds(obj) { |
362 | + if ( ! obj) |
363 | + return obj; |
364 | + |
365 | + if (!UnityWebAppsUtils.isIterableObject(obj)) { |
366 | + return obj; |
367 | + } |
368 | + |
369 | + if (obj |
370 | + && obj.hasOwnProperty('callbackid') |
371 | + && obj.callbackid !== null) { |
372 | + return this._makeWebpageCallback (obj.callbackid); |
373 | + } |
374 | + |
375 | + var ret = (obj instanceof Array) ? [] : {}; |
376 | + for (var key in obj) { |
377 | + if (obj.hasOwnProperty(key)) { |
378 | + if (UnityWebAppsUtils.isIterableObject (obj[key])) { |
379 | + if (obj[key].callbackid !== null) { |
380 | + ret[key] = this._makeWebpageCallback (obj[key].callbackid); |
381 | + } |
382 | + else { |
383 | + ret[key] = this._wrapCallbackIds (obj[key]); |
384 | + } |
385 | + } |
386 | + else { |
387 | + ret[key] = obj[key]; |
388 | + } |
389 | + } |
390 | + } |
391 | + return ret; |
392 | +} |
393 | |
394 | |
395 | === modified file 'src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js' |
396 | --- src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js 2014-03-18 18:52:11 +0000 |
397 | +++ src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js 2014-07-18 17:03:51 +0000 |
398 | @@ -137,6 +137,64 @@ |
399 | }, |
400 | |
401 | /** |
402 | + * \internal |
403 | + * |
404 | + */ |
405 | + _makeWebpageCallback: function (callbackid) { |
406 | + var self = this; |
407 | + return function () { |
408 | + var callback_args = Array.prototype.slice.call(arguments); |
409 | + |
410 | + callback_args = callback_args.map (function (arg) { |
411 | + return self._transformCallbacksToIds(arg); |
412 | + }); |
413 | + |
414 | + var message = formatUnityWebappsCallbackCall(callbackid, JSON.stringify(callback_args)); |
415 | + |
416 | + self._sendToBackend(JSON.stringify(message)); |
417 | + }; |
418 | + }, |
419 | + |
420 | + /** |
421 | + * \internal |
422 | + * |
423 | + * Wraps callback ids in proper callback that dispatch to the |
424 | + * webpage thru a proper event |
425 | + * |
426 | + */ |
427 | + _wrapCallbackIds: function (obj) { |
428 | + if ( ! obj) |
429 | + return obj; |
430 | + if ( ! isIterableObject(obj)) { |
431 | + return obj; |
432 | + } |
433 | + |
434 | + if (obj |
435 | + && obj.hasOwnProperty('callbackid') |
436 | + && obj.callbackid !== null) { |
437 | + return this._makeWebpageCallback (obj.callbackid); |
438 | + } |
439 | + |
440 | + var ret = (obj instanceof Array) ? [] : {}; |
441 | + for (var key in obj) { |
442 | + if (obj.hasOwnProperty(key)) { |
443 | + if (UnityWebAppsUtils.isIterableObject (obj[key])) { |
444 | + if (obj[key].callbackid != null) { |
445 | + ret[key] = this._makeWebpageCallback (obj[key].callbackid); |
446 | + } |
447 | + else { |
448 | + ret[key] = this._wrapCallbackIds (obj[key]); |
449 | + } |
450 | + } |
451 | + else { |
452 | + ret[key] = obj[key]; |
453 | + } |
454 | + } |
455 | + } |
456 | + return ret; |
457 | + }, |
458 | + |
459 | + /** |
460 | * @internal |
461 | */ |
462 | _dispatchCallbackCall: function(id, args) { |
463 | @@ -174,6 +232,11 @@ |
464 | else if (arg instanceof Array) { |
465 | return self._translateArgs(arg); |
466 | } |
467 | + else if (arg |
468 | + && arg.hasOwnProperty('callbackid') |
469 | + && arg.callbackid !== null) { |
470 | + return self._makeWebpageCallback (arg.callbackid); |
471 | + } |
472 | |
473 | return arg; |
474 | }); |
475 | |
476 | === renamed directory 'tests/integration/autopilot' => 'tests/autopilot' |
477 | === modified file 'tests/autopilot/autopilot.pro' |
478 | --- tests/integration/autopilot/autopilot.pro 2014-07-08 19:27:21 +0000 |
479 | +++ tests/autopilot/autopilot.pro 2014-07-18 17:03:51 +0000 |
480 | @@ -1,5 +1,16 @@ |
481 | TEMPLATE=aux |
482 | |
483 | +UNITY_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) |
484 | + |
485 | +inject_dependancies.target = ./html/test_webapps_callback_dispatch_api.js |
486 | +inject_dependancies.depends = ./html/test_webapps_callback_dispatch_api.js.in |
487 | +inject_dependancies.commands = $$PWD/../../tools/inject-js-utils.py $< $@ |
488 | + |
489 | +QMAKE_EXTRA_TARGETS += inject_dependancies |
490 | + |
491 | +PRE_TARGETDEPS += \ |
492 | + ./html/test_webapps_callback_dispatch_api.js |
493 | + |
494 | OTHER_FILES += \ |
495 | $$system(ls ./qml/*) \ |
496 | $$system(ls ./html/*) \ |
497 | @@ -11,4 +22,11 @@ |
498 | unity_webapps_qml/tests/fake_servers.py \ |
499 | qml/WebviewBackendWebkit.qml \ |
500 | qml/WebviewBackendOxide.qml \ |
501 | - qml/message-server.js |
502 | + qml/message-server.js \ |
503 | + $$system(ls ./data/installed-webapps/*) \ |
504 | + unity_webapps_qml/tests/test_callbackDispatch.py \ |
505 | + html/test_webapps_callback_dispatch.html \ |
506 | + html/test_webapps_callback_dispatch_api.js \ |
507 | + html/test_webapps_callback_dispatch_api.js.in \ |
508 | + qml/test_webapps_callback_dispatch_api.qml |
509 | + |
510 | |
511 | === added file 'tests/autopilot/html/test_webapps_callback_dispatch.html' |
512 | --- tests/autopilot/html/test_webapps_callback_dispatch.html 1970-01-01 00:00:00 +0000 |
513 | +++ tests/autopilot/html/test_webapps_callback_dispatch.html 2014-07-18 17:03:51 +0000 |
514 | @@ -0,0 +1,57 @@ |
515 | +<html> |
516 | + |
517 | +<head> |
518 | +<title>Unity Webapps QML test: callback</title> |
519 | + |
520 | +<script> |
521 | + |
522 | +window.onload = function () { |
523 | + var unity; |
524 | + function init() { |
525 | + unity = window.external.getUnityObject('1.0'); |
526 | + doCallbackLoop(); |
527 | + } |
528 | + |
529 | + var CALLBACK_COUNT_MAX_COUNT = 10; |
530 | + var callbackLoopCount = 0; |
531 | + function doCallbackLoop(callback) { |
532 | + if (callbackLoopCount >= CALLBACK_COUNT_MAX_COUNT) { |
533 | + document.getElementById('content').innerHTML = 'callback-loop-count-reached'; |
534 | + return; |
535 | + } |
536 | + ++callbackLoopCount; |
537 | + |
538 | + if (callback && typeof callback === 'Function') { |
539 | + callback(doCallbackLoop); |
540 | + } |
541 | + else { |
542 | + unity.withCallback(doCallbackLoop); |
543 | + } |
544 | + } |
545 | + |
546 | + init(); |
547 | + |
548 | + if (window.external.getUnityObject) { |
549 | + init(); |
550 | + } |
551 | + else { |
552 | + document.addEventListener('ubuntu-webapps-api-ready', function () { |
553 | + init(); |
554 | + }, false); |
555 | + } |
556 | +} |
557 | + |
558 | +</script> |
559 | + |
560 | +</head> |
561 | + |
562 | +<body> |
563 | + |
564 | +HELLO WORLD |
565 | + |
566 | +<div id="content"> |
567 | +</div> |
568 | + |
569 | +</body> |
570 | + |
571 | +</html> |
572 | |
573 | === added file 'tests/autopilot/html/test_webapps_callback_dispatch_api.js.in' |
574 | --- tests/autopilot/html/test_webapps_callback_dispatch_api.js.in 1970-01-01 00:00:00 +0000 |
575 | +++ tests/autopilot/html/test_webapps_callback_dispatch_api.js.in 2014-07-18 17:03:51 +0000 |
576 | @@ -0,0 +1,58 @@ |
577 | +/* |
578 | + * Copyright 2014 Canonical Ltd. |
579 | + * |
580 | + * This file is part of unity-webapps-qml. |
581 | + * |
582 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
583 | + * it under the terms of the GNU General Public License as published by |
584 | + * the Free Software Foundation; version 3. |
585 | + * |
586 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
587 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
588 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
589 | + * GNU General Public License for more details. |
590 | + * |
591 | + * You should have received a copy of the GNU General Public License |
592 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
593 | + */ |
594 | + |
595 | +(function () { |
596 | + |
597 | + // Acknowledge that the API has been fully injected |
598 | + var sendApiCreatedAcknowledgeEvent = function () { |
599 | + var e = document.createEvent ("Events"); |
600 | + e.initEvent ("ubuntu-webapps-api-ready", false, false); |
601 | + document.dispatchEvent (e); |
602 | + }; |
603 | + |
604 | + //@include ../../src/Ubuntu/UnityWebApps/UnityWebAppsUtils.js |
605 | + //@include ../../src/Ubuntu/UnityWebApps/common/js/unity-backend-messaging-proxy.js |
606 | + //@include ../../src/Ubuntu/UnityWebApps/common/js/unity-binding-proxy.js |
607 | + //@include ../../src/Ubuntu/UnityWebApps/common/js/unity-binding-bridge.js |
608 | + |
609 | + var apiBuilder = function(backend) { |
610 | + return { |
611 | + withCallback: function(callback) { |
612 | + backend.call('withCallback', [callback]); |
613 | + } |
614 | + }; |
615 | + }; |
616 | + |
617 | + var apiBridge = new UnityBindingBridge( |
618 | + makeCallbackManager(), |
619 | + createMessagingProxyForCurrentWebRuntime()); |
620 | + |
621 | + var api = apiBuilder (apiBridge); |
622 | + |
623 | + apiBridge.setBindingApi(api); |
624 | + |
625 | + if (!window.external) |
626 | + window.external = {}; |
627 | + |
628 | + window.external.getUnityObject = function (version) { |
629 | + return api; |
630 | + }; |
631 | + |
632 | + sendApiCreatedAcknowledgeEvent(); |
633 | +}) (); |
634 | + |
635 | |
636 | === modified file 'tests/autopilot/qml/FullWebViewApp.qml' |
637 | --- tests/integration/autopilot/qml/FullWebViewApp.qml 2014-07-08 19:27:21 +0000 |
638 | +++ tests/autopilot/qml/FullWebViewApp.qml 2014-07-18 17:03:51 +0000 |
639 | @@ -51,6 +51,10 @@ |
640 | |
641 | property bool useOxide: false |
642 | property string url: "" |
643 | + |
644 | + property string apiBackendQmlFileUrl: "" |
645 | + property string clientApiFileUrl: "" |
646 | + |
647 | property string webappName: "" |
648 | property string webappSearchPath: "" |
649 | property string webappHomepage: "" |
650 | @@ -82,9 +86,18 @@ |
651 | } |
652 | |
653 | Loader { |
654 | + id: apiBackendQmlFileLoader |
655 | + source: apiBackendQmlFileUrl.length !== 0 ? apiBackendQmlFileUrl : "" |
656 | + } |
657 | + |
658 | + Loader { |
659 | id: unityWebappsComponentLoader |
660 | anchors.fill: parent |
661 | - sourceComponent: webView !== null && webappName.length !== 0 ? unityWebappsComponent : null |
662 | + sourceComponent: (webView !== null && webappName.length !== 0) ? |
663 | + (apiBackendQmlFileUrl.length !== 0 ? |
664 | + (apiBackendQmlFileLoader.item ? unityWebappsComponent : undefined) |
665 | + : unityWebappsComponent) |
666 | + : null |
667 | } |
668 | |
669 | UnityWebappsAppModel { |
670 | @@ -100,9 +113,15 @@ |
671 | objectName: "webappsContainer" |
672 | actionsContext: webappsActionsContext |
673 | name: root.webappName |
674 | + injectExtraUbuntuApis: true |
675 | + customBackendProxies: apiBackendQmlFileLoader.item |
676 | + ? apiBackendQmlFileLoader.item.buildapi() |
677 | + : undefined |
678 | + customClientApiFileUrl: root.clientApiFileUrl |
679 | bindee: webView |
680 | _opt_homepage: root.webappHomepage |
681 | model: webappModel |
682 | } |
683 | } |
684 | } |
685 | + |
686 | |
687 | === added file 'tests/autopilot/qml/test_webapps_callback_dispatch_api.qml' |
688 | --- tests/autopilot/qml/test_webapps_callback_dispatch_api.qml 1970-01-01 00:00:00 +0000 |
689 | +++ tests/autopilot/qml/test_webapps_callback_dispatch_api.qml 2014-07-18 17:03:51 +0000 |
690 | @@ -0,0 +1,14 @@ |
691 | +import QtQuick 2.0 |
692 | + |
693 | +Item { |
694 | + function buildapi() { |
695 | + return { |
696 | + withCallback: function(clientCallback) { |
697 | + function callbackLoop(callback) { |
698 | + callback(callbackLoop); |
699 | + } |
700 | + clientCallback(callbackLoop); |
701 | + } |
702 | + }; |
703 | + } |
704 | +} |
705 | |
706 | === modified file 'tests/autopilot/unity_webapps_qml/tests/__init__.py' |
707 | --- tests/integration/autopilot/unity_webapps_qml/tests/__init__.py 2014-07-08 19:27:21 +0000 |
708 | +++ tests/autopilot/unity_webapps_qml/tests/__init__.py 2014-07-18 17:03:51 +0000 |
709 | @@ -21,7 +21,7 @@ |
710 | |
711 | from unity.tests import UnityTestCase |
712 | |
713 | -LOCAL_QML_LAUNCHER_APP_PATH = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../../../../tools/qml-launcher/unity-webapps-qml-launcher') |
714 | +LOCAL_QML_LAUNCHER_APP_PATH = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../../../tools/qml-launcher/unity-webapps-qml-launcher') |
715 | INSTALLED_QML_LAUNCHER_APP_PATH = 'unity-webapps-qml-launcher' |
716 | |
717 | # TODO create __init__.py.in |
718 | @@ -31,6 +31,7 @@ |
719 | BASE_URL = '' |
720 | |
721 | class UnityWebappsTestCaseBase(UnityTestCase): |
722 | + |
723 | def setUp(self): |
724 | super(UnityWebappsTestCaseBase, self).setUp() |
725 | self.use_oxide = False |
726 | @@ -56,7 +57,8 @@ |
727 | webapp_name='unitywebappsqmllauncher', |
728 | webapp_search_path="", |
729 | webapp_homepage="", |
730 | - use_oxide=False): |
731 | + use_oxide=False, |
732 | + extra_params=[]): |
733 | base_params = ['--qml=' + self.get_qml_browser_container_path(), |
734 | '--app-id=' + webapp_name, |
735 | '--webappName=' + webapp_name, |
736 | @@ -74,15 +76,17 @@ |
737 | if os.path.exists(LOCAL_QML_LAUNCHER_APP_PATH): |
738 | # we are local |
739 | base_params.append('--import=' + os.path.join (os.path.dirname(os.path.realpath(__file__)), |
740 | - '../../../../../src')) |
741 | + '../../../../src')) |
742 | + |
743 | + base_params += extra_params |
744 | |
745 | return base_params |
746 | |
747 | - def launch_with_html_filepath(self, html_filepath): |
748 | + def launch_with_html_filepath(self, html_filepath, extra_params=[]): |
749 | self.assertThat(os.path.exists(html_filepath), Equals(True)) |
750 | url = self.create_file_url(html_filepath) |
751 | |
752 | - self.launch_application(self.get_launch_params(url)) |
753 | + self.launch_application(self.get_launch_params(url, 'unitywebappsqmllauncher', '', '', False, extra_params)) |
754 | self.assert_url_eventually_loaded(url) |
755 | |
756 | def launch_application(self, args): |
757 | |
758 | === added file 'tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py' |
759 | --- tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py 1970-01-01 00:00:00 +0000 |
760 | +++ tests/autopilot/unity_webapps_qml/tests/test_callbackDispatch.py 2014-07-18 17:03:51 +0000 |
761 | @@ -0,0 +1,60 @@ |
762 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
763 | +# Copyright 2014 Canonical |
764 | +# |
765 | +# This program is free software: you can redistribute it and/or modify it |
766 | +# under the terms of the GNU General Public License version 3, as published |
767 | +# by the Free Software Foundation. |
768 | + |
769 | +from __future__ import absolute_import |
770 | + |
771 | +import time |
772 | +import os |
773 | + |
774 | +from testtools.matchers import Equals, GreaterThan, NotEquals |
775 | +from autopilot.matchers import Eventually |
776 | + |
777 | +from unity_webapps_qml.tests import UnityWebappsTestCaseBase |
778 | + |
779 | +LOCAL_HTML_TEST_FILE = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../html/test_webapps_callback_dispatch.html') |
780 | +INSTALLED_HTML_TEST_FILE = '/usr/share/unity-webapps-qml/autopilot-tests/html/test_webapps_callback_dispatch.html' |
781 | + |
782 | +LOCAL_JS_TEST_FILE = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../html/test_webapps_callback_dispatch_api.js') |
783 | +INSTALLED_JS_TEST_FILE = '/usr/share/unity-webapps-qml/autopilot-tests/html/test_webapps_callback_dispatch_api.js' |
784 | + |
785 | +LOCAL_QML_BACKEND_TEST_FILE = "%s/%s" % (os.path.dirname(os.path.realpath(__file__)), '../../qml/test_webapps_callback_dispatch_api.qml') |
786 | +INSTALLED_QML_BACKEND_TEST_FILE = '/usr/share/unity-webapps-qml/autopilot-tests/qml/test_webapps_callback_dispatch_api.qml' |
787 | + |
788 | +class WebappsCallbackDispatchTestCaseBase(UnityWebappsTestCaseBase): |
789 | + def setUp(self): |
790 | + super(WebappsCallbackDispatchTestCaseBase, self).setUp() |
791 | + self.launch_with_html_filepath( |
792 | + self.get_html_test_file(), |
793 | + ['--clientApiFileUrl=file://' + self.get_js_test_file(), |
794 | + '--apiBackendQmlFileUrl=file://' + self.get_qml_test_file()]) |
795 | + |
796 | + def get_html_test_file(self): |
797 | + if os.path.exists(LOCAL_HTML_TEST_FILE): |
798 | + return os.path.abspath(LOCAL_HTML_TEST_FILE) |
799 | + return INSTALLED_HTML_TEST_FILE |
800 | + |
801 | + def get_js_test_file(self): |
802 | + if os.path.exists(LOCAL_JS_TEST_FILE): |
803 | + return os.path.abspath(LOCAL_JS_TEST_FILE) |
804 | + return INSTALLED_JS_TEST_FILE |
805 | + |
806 | + def get_qml_test_file(self): |
807 | + print LOCAL_QML_BACKEND_TEST_FILE |
808 | + if os.path.exists(LOCAL_QML_BACKEND_TEST_FILE): |
809 | + return os.path.abspath(LOCAL_QML_BACKEND_TEST_FILE) |
810 | + return INSTALLED_QML_BACKEND_TEST_FILE |
811 | + |
812 | + def test_bidirectionalCallback(self): |
813 | + self.assertThat( |
814 | + lambda: self.eval_expression_in_page_unsafe( |
815 | + 'return window.external.getUnityObject("1.0") != null;'), |
816 | + Eventually(Equals(True))) |
817 | + |
818 | + self.assertThat( |
819 | + lambda: self.eval_expression_in_page_unsafe("return document.getElementById('content').innerHTML;"), |
820 | + Eventually(Equals('callback-loop-count-reached'))) |
821 | + |
822 | |
823 | === removed directory 'tests/integration' |
824 | === removed file 'tests/integration/integration.pro' |
825 | --- tests/integration/integration.pro 2013-07-09 19:02:23 +0000 |
826 | +++ tests/integration/integration.pro 1970-01-01 00:00:00 +0000 |
827 | @@ -1,3 +0,0 @@ |
828 | -TEMPLATE = subdirs |
829 | - |
830 | -SUBDIRS = autopilot |
831 | |
832 | === modified file 'tests/tests.pro' |
833 | --- tests/tests.pro 2013-07-24 20:31:38 +0000 |
834 | +++ tests/tests.pro 2014-07-18 17:03:51 +0000 |
835 | @@ -1,4 +1,4 @@ |
836 | TEMPLATE=subdirs |
837 | |
838 | -SUBDIRS = unit integration |
839 | +SUBDIRS = unit autopilot |
840 | |
841 | |
842 | === modified file 'tests/unit/test_qml/tst_dispatch.qml' |
843 | --- tests/unit/test_qml/tst_dispatch.qml 2014-04-14 20:57:17 +0000 |
844 | +++ tests/unit/test_qml/tst_dispatch.qml 2014-07-18 17:03:51 +0000 |
845 | @@ -19,7 +19,7 @@ |
846 | |
847 | var simple_backend = {This: { Is: { A: {Backend: function (args) { mockedWebView.called(args) } } } } }; |
848 | |
849 | - webapps._opt_backendProxies = simple_backend; |
850 | + webapps.customBackendProxies = simple_backend; |
851 | webapps.name = "test_properBackendDispatched"; |
852 | webapps.bindee = mockedWebView; |
853 | |
854 | @@ -47,7 +47,7 @@ |
855 | |
856 | var simple_backend = {This: { Is: { A: {Backend: action } } } }; |
857 | |
858 | - webapps._opt_backendProxies = simple_backend; |
859 | + webapps.customBackendProxies = simple_backend; |
860 | webapps.name = "test_backendDispatchedWithProperArguments"; |
861 | webapps.bindee = mockedWebView; |
862 | |
863 | @@ -65,7 +65,7 @@ |
864 | |
865 | var invalid_backend = {This: { Is: { Not: { A: {Backend: function (args) { mockedWebView.called(args) } } } } } }; |
866 | |
867 | - webapps._opt_backendProxies = invalid_backend; |
868 | + webapps.customBackendProxies = invalid_backend; |
869 | webapps.name = "test_invalidBackendNotDispatched"; |
870 | webapps.bindee = mockedWebView; |
871 | |
872 | @@ -94,7 +94,7 @@ |
873 | |
874 | var backend = {This: { Is: { A: {Backend: action } } } }; |
875 | |
876 | - webapps._opt_backendProxies = backend; |
877 | + webapps.customBackendProxies = backend; |
878 | webapps.name = "test_callbacksAreWrapped"; |
879 | webapps.bindee = mockedWebView; |
880 | |
881 | |
882 | === modified file 'tools/qml-launcher/qml-launcher.cpp' |
883 | --- tools/qml-launcher/qml-launcher.cpp 2014-07-08 19:27:21 +0000 |
884 | +++ tools/qml-launcher/qml-launcher.cpp 2014-07-18 17:03:51 +0000 |
885 | @@ -119,17 +119,17 @@ |
886 | |
887 | QString value = argument.right(argument.count() - argument.indexOf(VALUE_HEADER) - 1); |
888 | |
889 | - qDebug() << "Adding property: " |
890 | + qDebug() << "Adding property:" |
891 | << property |
892 | - << ", " |
893 | - << "value: " |
894 | + << "," |
895 | + << "value:" |
896 | << value; |
897 | |
898 | properties.insert(property, value); |
899 | } |
900 | else |
901 | { |
902 | - qDebug() << "Ignoring argument: " << argument; |
903 | + qDebug() << "Ignoring argument:" << argument; |
904 | } |
905 | } |
906 | |
907 | @@ -147,13 +147,13 @@ |
908 | QFileInfo f(qmlfile); |
909 | if (!f.exists() || !f.isFile()) |
910 | { |
911 | - qDebug() << "QML file not found or not a file: " << qmlfile; |
912 | + qDebug() << "QML file not found or not a file:" << qmlfile; |
913 | return EXIT_FAILURE; |
914 | } |
915 | |
916 | if ( ! importPath.isEmpty()) |
917 | { |
918 | - qDebug() << "Setting import path to: " << importPath; |
919 | + qDebug() << "Setting import path to:" << importPath; |
920 | qputenv("QML2_IMPORT_PATH", importPath.toLatin1()); |
921 | } |
922 | |
923 | @@ -167,7 +167,7 @@ |
924 | |
925 | if ( ! inspector.isEmpty()) |
926 | { |
927 | - qDebug() << "Inspector server being set to: " << inspector; |
928 | + qDebug() << "Inspector server being set to:" << inspector; |
929 | |
930 | qputenv("QTWEBKIT_INSPECTOR_SERVER", inspector.toLatin1()); |
931 | } |
932 | @@ -202,7 +202,6 @@ |
933 | if (useOxide) { |
934 | object->setProperty("useOxide", true); |
935 | } |
936 | - |
937 | component.completeCreate(); |
938 | |
939 | if (window) |
FAILED: Continuous integration, rev:135 jenkins. qa.ubuntu. com/job/ unity-webapps- qml-ci/ 138/ jenkins. qa.ubuntu. com/job/ unity-webapps- qml-utopic- amd64-ci/ 24/console jenkins. qa.ubuntu. com/job/ unity-webapps- qml-utopic- armhf-ci/ 24/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- webapps- qml-ci/ 138/rebuild
http://