Merge lp:~abreu-alexandre/unity-webapps-qml/application-api into lp:unity-webapps-qml
- application-api
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 102 |
Proposed branch: | lp:~abreu-alexandre/unity-webapps-qml/application-api |
Merge into: | lp:unity-webapps-qml |
Diff against target: |
1421 lines (+1185/-9) 20 files modified
examples/api-bindings/alarm/www/index.html (+4/-0) examples/api-bindings/content-hub-exporter/www/index.html (+4/-0) examples/api-bindings/content-hub/www/index.html (+4/-0) examples/api-bindings/online-accounts/www/index.html (+4/-0) examples/api-bindings/runtime-api/main.qml.in (+32/-0) examples/api-bindings/runtime-api/www/index.html (+22/-0) examples/api-bindings/runtime-api/www/js/app.js (+57/-0) src/Ubuntu/UnityWebApps/UnityWebApps.pro (+22/-7) src/Ubuntu/UnityWebApps/UnityWebApps.qml (+3/-0) src/Ubuntu/UnityWebApps/bindings/runtime-api/backend/runtime-api.js (+171/-0) src/Ubuntu/UnityWebApps/bindings/runtime-api/client/runtime-api.js (+256/-0) src/Ubuntu/UnityWebApps/plugin/application-api.cpp (+287/-0) src/Ubuntu/UnityWebApps/plugin/application-api.h (+75/-0) src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.cpp (+139/-0) src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.h (+62/-0) src/Ubuntu/UnityWebApps/plugin/plugin.pro (+6/-2) src/Ubuntu/UnityWebApps/plugin/qml-plugin.cpp (+15/-0) src/Ubuntu/UnityWebApps/unity-webapps-api.js.in (+2/-0) tests/unit/test_plugin/tst_plugin.cpp (+19/-0) tests/unit/test_plugin/tst_plugin.h (+1/-0) |
To merge this branch: | bzr merge lp:~abreu-alexandre/unity-webapps-qml/application-api |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alberto Mardegan (community) | Needs Fixing | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+212727@code.launchpad.net |
Commit message
Add application api
Description of the change
Add application api
Alberto Mardegan (mardy) wrote : | # |
Alexandre Abreu (abreu-alexandre) wrote : | # |
> I tested it and it's mostly working. A few comments:
>
> getPlatformInfos: I think it's better to call it "getPlatformInfo" without the
> final "s". Anyway, this just returns the name of the QPA plugin, so I'd rather
> rename the method to "getPlatformName" or keep the current name and make it
> return a dictionary, currently having only one field "name" which contains the
> platform name. But I'd take the second approach only if you really plan to add
> more info there in the future.
done,
> The example expects the onActivated() and onDeactivated() signal to carry a
> parameter, but they don't.
done,
> All the methods are asynchronous and take a callback; even the
> applicationName() function is asynchronous, even if the result is immediately
> available. I'm not familiar with HTML5 development so this might be perfectly
> fine, I just point this out because coming from the C++ world this sounds
> rather strange (and a bit inconvenient).
right, agree, took another approach,
> Naming: it's better to use the same convention for all the getters: either
> start their name always with a "get", or never. Most of the methods you added
> start with "get", but "applicationName" doesn't.
done,
> getInputMethod(): it's not very clear what this function does; maybe rename it
> to "getInputMethod
done,
> nameFromScreenO
> and "Portrait", while Qt supports 4. I guess that most apps don't care about
> distinguishing between the extra modes, but maybe some do (to be sure that the
> mic is on a specific side, for instance)?
right, agree, done
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:99
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 102. By Alexandre Abreu
-
merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:102
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Mardegan (mardy) wrote : | # |
I think there's a problem with how the getters are implemented. Let's take getScreenOrient
I'm not sure how expensive the switch betwenn client and backend is, so depending on that:
1) If the switch is not very expensive: don't cache any values in the client, always request the properties directly from the backend.
2) If the switch is very expensive, do as you are doing, but register an internal callback to the cached properties in the Application constructor. Something like:
var self = this;
this._name = content.name;
this.
(In the latter case we might even want to avoid passing through the backend when the client calls onApplicationNa
Can you also make the getInputMethodName return the value immediately?
Other than that, it all looks good to me!
Alexandre Abreu (abreu-alexandre) wrote : | # |
> I think there's a problem with how the getters are implemented. Let's take
> getScreenOrient
> retrieve the application name which was setup, which is correct. If the
> application registers a callback with onScreenOrienta
> this._screenOri
> getScreenOrient
> application doesn't call onScreenOrienta
> will never be updated and getScreenOrient
> value.
>
> I'm not sure how expensive the switch betwenn client and backend is, so
> depending on that:
>
> 1) If the switch is not very expensive: don't cache any values in the client,
> always request the properties directly from the backend.
>
> 2) If the switch is very expensive, do as you are doing, but register an
> internal callback to the cached properties in the Application constructor.
> Something like:
>
> var self = this;
> this._name = content.name;
> this._proxy.
> name; }]);
>
> (In the latter case we might even want to avoid passing through the backend
> when the client calls onApplicationNa
> function callback into an array (this._
> callback registered in the Application constructor we could then invoke all
> the callbacks in this._applicati
> "self._name = name")
>
>
> Can you also make the getInputMethodName return the value immediately?
all done
Preview Diff
1 | === modified file 'examples/api-bindings/alarm/www/index.html' |
2 | --- examples/api-bindings/alarm/www/index.html 2014-01-22 20:38:52 +0000 |
3 | +++ examples/api-bindings/alarm/www/index.html 2014-03-26 15:53:02 +0000 |
4 | @@ -1,5 +1,9 @@ |
5 | +<!DOCTYPE html> |
6 | <html> |
7 | |
8 | + <meta charset="utf-8" /> |
9 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
10 | + |
11 | <head> |
12 | <title>Content Hub example</title> |
13 | <script src="./js/app.js"></script> |
14 | |
15 | === modified file 'examples/api-bindings/content-hub-exporter/www/index.html' |
16 | --- examples/api-bindings/content-hub-exporter/www/index.html 2014-01-31 01:44:10 +0000 |
17 | +++ examples/api-bindings/content-hub-exporter/www/index.html 2014-03-26 15:53:02 +0000 |
18 | @@ -1,5 +1,9 @@ |
19 | +<!DOCTYPE html> |
20 | <html> |
21 | |
22 | + <meta charset="utf-8" /> |
23 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
24 | + |
25 | <head> |
26 | <title>Content Hub Exporter example</title> |
27 | <script src="./js/app.js"></script> |
28 | |
29 | === modified file 'examples/api-bindings/content-hub/www/index.html' |
30 | --- examples/api-bindings/content-hub/www/index.html 2014-02-08 14:48:32 +0000 |
31 | +++ examples/api-bindings/content-hub/www/index.html 2014-03-26 15:53:02 +0000 |
32 | @@ -1,5 +1,9 @@ |
33 | +<!DOCTYPE html> |
34 | <html> |
35 | |
36 | + <meta charset="utf-8" /> |
37 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
38 | + |
39 | <head> |
40 | <title>Content Hub example</title> |
41 | <script src="./js/app.js"></script> |
42 | |
43 | === modified file 'examples/api-bindings/online-accounts/www/index.html' |
44 | --- examples/api-bindings/online-accounts/www/index.html 2014-02-26 13:21:37 +0000 |
45 | +++ examples/api-bindings/online-accounts/www/index.html 2014-03-26 15:53:02 +0000 |
46 | @@ -1,5 +1,9 @@ |
47 | +<!DOCTYPE html> |
48 | <html> |
49 | |
50 | + <meta charset="utf-8" /> |
51 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
52 | + |
53 | <head> |
54 | <title>Content Hub example</title> |
55 | <script src="./js/app.js"></script> |
56 | |
57 | === added directory 'examples/api-bindings/runtime-api' |
58 | === added file 'examples/api-bindings/runtime-api/main.qml.in' |
59 | --- examples/api-bindings/runtime-api/main.qml.in 1970-01-01 00:00:00 +0000 |
60 | +++ examples/api-bindings/runtime-api/main.qml.in 2014-03-26 15:53:02 +0000 |
61 | @@ -0,0 +1,32 @@ |
62 | +import QtQuick 2.0 |
63 | +import QtWebKit 3.0 |
64 | +import QtWebKit.experimental 1.0 |
65 | +import Ubuntu.Components 0.1 |
66 | +import Ubuntu.UnityWebApps 0.1 |
67 | + |
68 | +MainView { |
69 | + id: root |
70 | + focus: true |
71 | + applicationName: \"runtime-api\" |
72 | + |
73 | + width: units.gu(100) |
74 | + height: units.gu(100) |
75 | + |
76 | + WebView { |
77 | + id: webview |
78 | + anchors.fill: parent |
79 | + url: \"file://$$OUT_PWD/runtime-api/www/index.html\" |
80 | + |
81 | + experimental.preferences.navigatorQtObjectEnabled: true |
82 | + experimental.preferences.developerExtrasEnabled: true |
83 | + |
84 | + function getUnityWebappsProxies() { |
85 | + return UnityWebAppsUtils.makeProxiesForQtWebViewBindee(webview); |
86 | + } |
87 | + |
88 | + UnityWebApps { |
89 | + id: webapps |
90 | + bindee: webview |
91 | + } |
92 | + } |
93 | +} |
94 | |
95 | === added directory 'examples/api-bindings/runtime-api/www' |
96 | === added file 'examples/api-bindings/runtime-api/www/index.html' |
97 | --- examples/api-bindings/runtime-api/www/index.html 1970-01-01 00:00:00 +0000 |
98 | +++ examples/api-bindings/runtime-api/www/index.html 2014-03-26 15:53:02 +0000 |
99 | @@ -0,0 +1,22 @@ |
100 | +<!DOCTYPE html> |
101 | +<html> |
102 | + |
103 | + <meta charset="utf-8" /> |
104 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
105 | + |
106 | + <head> |
107 | + <title>Runtime Api example</title> |
108 | + <script src="./js/app.js"></script> |
109 | + </head> |
110 | + |
111 | + <body> |
112 | + |
113 | + <div> |
114 | + Results: |
115 | + <div id="results"> |
116 | + </div> |
117 | + </div> |
118 | + |
119 | + </body> |
120 | + |
121 | +</html> |
122 | |
123 | === added directory 'examples/api-bindings/runtime-api/www/js' |
124 | === added file 'examples/api-bindings/runtime-api/www/js/app.js' |
125 | --- examples/api-bindings/runtime-api/www/js/app.js 1970-01-01 00:00:00 +0000 |
126 | +++ examples/api-bindings/runtime-api/www/js/app.js 2014-03-26 15:53:02 +0000 |
127 | @@ -0,0 +1,57 @@ |
128 | +window.onload = function() { |
129 | + function setResult(message) { |
130 | + var results = document.getElementById('results'); |
131 | + results.innerHTML += message + '<br>'; |
132 | + } |
133 | + |
134 | + var last = 0; |
135 | + if (localStorage.getItem("lastkilled") !== null) |
136 | + last = localStorage.getItem("lastkilled"); |
137 | + |
138 | + setResult('last killed: ' + last); |
139 | + |
140 | + var api = external.getUnityObject('1.0'); |
141 | + |
142 | + api.RuntimeApi.getApplication(function(application) { |
143 | + setResult('application name: ' + application.getApplicationName()); |
144 | + setResult('application info: ' + JSON.stringify(application.getPlatformInfo())); |
145 | + |
146 | + application.getInputMethodName(function(name) { |
147 | + if (name.length == 0) |
148 | + setResult('input method: no OSK available'); |
149 | + else |
150 | + setResult('input method: ' + name); |
151 | + }); |
152 | + |
153 | + setResult('screen orientation: ' + application.getScreenOrientation()); |
154 | + |
155 | + application.onScreenOrientationChanged(function(name) { |
156 | + setResult('Event: orientation changed - ' + name); |
157 | + }); |
158 | + |
159 | + application.onAboutToQuit(function(killed) { |
160 | + localStorage.setItem("lastkilled", last + 1); |
161 | + |
162 | + console.log('killed: ' + killed) |
163 | + |
164 | + setResult('onAboutToQuit: ' + killed); |
165 | + }); |
166 | + |
167 | + application.onDeactivated(function() { |
168 | + setResult('Event: application deactivated'); |
169 | + }); |
170 | + |
171 | + application.onActivated(function() { |
172 | + setResult('Event: application activated'); |
173 | + }); |
174 | + |
175 | + application.onInputMethodVisibilityChanged(function(visibility) { |
176 | + setResult('Event: onInputMethodVisibilityChanged - ' + visibility); |
177 | + }); |
178 | + |
179 | + application.setupUriHandler(function(uris) { |
180 | + setResult('Event: received URI to open w/ UriHandler - ' + JSON.stringify(uris)); |
181 | + }); |
182 | + |
183 | + }); |
184 | +}; |
185 | |
186 | === modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.pro' |
187 | --- src/Ubuntu/UnityWebApps/UnityWebApps.pro 2014-01-17 15:51:27 +0000 |
188 | +++ src/Ubuntu/UnityWebApps/UnityWebApps.pro 2014-03-26 15:53:02 +0000 |
189 | @@ -21,10 +21,13 @@ |
190 | # |
191 | # deployment directives |
192 | # |
193 | -JS_FILES = $$system(ls *.js) \ |
194 | - $${UNITY_API_JS_FILE} \ |
195 | +PLUGIN_JS_FILES = \ |
196 | + $$system(ls *.js) \ |
197 | + $${UNITY_API_JS_FILE} |
198 | + |
199 | +CLIENT_JS_FILES = \ |
200 | $$system(ls ./common/*/*.js) \ |
201 | - $$system(ls ./bindings/*/*/*.js) |
202 | + $$system(ls ./bindings/*/client/*.js) |
203 | |
204 | QML_FILES = $$system(ls *.qml) |
205 | |
206 | @@ -32,7 +35,9 @@ |
207 | QMAKE_SUBSTITUTES += qmldir.in |
208 | |
209 | OTHER_FILES += $$QML_FILES \ |
210 | - $$JS_FILES \ |
211 | + $$PLUGIN_JS_FILES \ |
212 | + $$CLIENT_JS_FILES \ |
213 | + $$system(ls ./bindings/*/backend/*.js) \ |
214 | qmldir.in \ |
215 | unity-webapps-api.js.in \ |
216 | $${UNITY_API_JS_FILE} |
217 | @@ -44,9 +49,19 @@ |
218 | |
219 | qmldir_file.path = $$installPath |
220 | qmldir_file.files = $$QMLDIR_FILE |
221 | + |
222 | qml_files.path = $$installPath |
223 | qml_files.files = $$QML_FILES |
224 | + |
225 | js_files.path = $$installPath |
226 | -js_files.files = $$JS_FILES |
227 | - |
228 | -INSTALLS += qmldir_file qml_files js_files |
229 | +js_files.files = $$PLUGIN_JS_FILES |
230 | + |
231 | +runtime_api_binding_backend_js_files.path = $$installPath/bindings/runtime-api/backend/ |
232 | +runtime_api_binding_backend_js_files.files = ./bindings/runtime-api/backend/runtime-api.js |
233 | + |
234 | +INSTALLS += qmldir_file \ |
235 | + qml_files \ |
236 | + js_files \ |
237 | + runtime_api_binding_backend_js_files \ |
238 | + |
239 | + |
240 | |
241 | === modified file 'src/Ubuntu/UnityWebApps/UnityWebApps.qml' |
242 | --- src/Ubuntu/UnityWebApps/UnityWebApps.qml 2014-03-17 17:25:53 +0000 |
243 | +++ src/Ubuntu/UnityWebApps/UnityWebApps.qml 2014-03-26 15:53:02 +0000 |
244 | @@ -21,6 +21,7 @@ |
245 | import "UnityWebApps.js" as UnityWebAppsJs |
246 | import "UnityWebAppsUtils.js" as UnityWebAppsJsUtils |
247 | import "UnityWebAppsBackendComponents.js" as UnityBackends |
248 | +import "./bindings/runtime-api/backend/runtime-api.js" as RuntimeApiBackend |
249 | |
250 | |
251 | /*! |
252 | @@ -649,6 +650,8 @@ |
253 | return UnityBackends.createContentHubApi(UnityBackends.backendDelegate) |
254 | }), |
255 | |
256 | + RuntimeApi: RuntimeApiBackend.createRuntimeApi(UnityBackends.backendDelegate), |
257 | + |
258 | Launcher: { |
259 | setCount: function (count) { |
260 | if (!initialized) |
261 | |
262 | === added directory 'src/Ubuntu/UnityWebApps/bindings/runtime-api' |
263 | === added directory 'src/Ubuntu/UnityWebApps/bindings/runtime-api/backend' |
264 | === added file 'src/Ubuntu/UnityWebApps/bindings/runtime-api/backend/runtime-api.js' |
265 | --- src/Ubuntu/UnityWebApps/bindings/runtime-api/backend/runtime-api.js 1970-01-01 00:00:00 +0000 |
266 | +++ src/Ubuntu/UnityWebApps/bindings/runtime-api/backend/runtime-api.js 2014-03-26 15:53:02 +0000 |
267 | @@ -0,0 +1,171 @@ |
268 | +/* |
269 | + * Copyright 2014 Canonical Ltd. |
270 | + * |
271 | + * This file is part of unity-webapps-qml. |
272 | + * |
273 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
274 | + * it under the terms of the GNU General Public License as published by |
275 | + * the Free Software Foundation; version 3. |
276 | + * |
277 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
278 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
279 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
280 | + * GNU General Public License for more details. |
281 | + * |
282 | + * You should have received a copy of the GNU General Public License |
283 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
284 | + */ |
285 | + |
286 | +.import Ubuntu.UnityWebApps 0.1 as UnityWebAppsBridge |
287 | +.import Ubuntu.Components 0.1 as ComponentsBridge |
288 | + |
289 | + |
290 | +/** |
291 | + * |
292 | + * Runtime API backend binding |
293 | + * |
294 | + */ |
295 | +function createRuntimeApi(backendDelegate) { |
296 | + var PLUGIN_URI = 'Ubuntu.UnityWebApps'; |
297 | + var VERSION = 0.1; |
298 | + |
299 | + var applicationApiInstance = UnityWebAppsBridge.ApplicationApi; |
300 | + |
301 | + function Application() { |
302 | + // no need to have a specific id since this class is mostly a passtrough one |
303 | + this._id = 0; |
304 | + }; |
305 | + Application.prototype = { |
306 | + |
307 | + // object methods |
308 | + serialize: function() { |
309 | + var self = this; |
310 | + return { |
311 | + type: 'object-proxy', |
312 | + apiid: 'RuntimeApi', |
313 | + objecttype: 'Application', |
314 | + objectid: this._id, |
315 | + |
316 | + content: { |
317 | + name: applicationApiInstance.applicationName, |
318 | + platform: applicationApiInstance.applicationPlatform, |
319 | + writableLocation: applicationApiInstance.applicationDataPath, |
320 | + screenOrientation: applicationApiInstance.screenOrientation, |
321 | + } |
322 | + } |
323 | + }, |
324 | + |
325 | + getApplicationName: function(callback) { |
326 | + if (callback && typeof(callback) === 'function') |
327 | + callback(applicationApiInstance.applicationName); |
328 | + }, |
329 | + onApplicationNameChanged: function(callback) { |
330 | + if (callback && typeof(callback) === 'function') |
331 | + applicationApiInstance.applicationNameChanged.connect(function() { |
332 | + callback(applicationApiInstance.applicationName); |
333 | + }); |
334 | + }, |
335 | + |
336 | + getApplicationWritableLocation: function(callback) { |
337 | + if (callback && typeof(callback) === 'function') |
338 | + callback(applicationApiInstance.applicationDataPath); |
339 | + }, |
340 | + |
341 | + getPlatformInfo: function(callback) { |
342 | + if (callback && typeof(callback) === 'function') { |
343 | + var info = {}; |
344 | + info.name = applicationApiInstance.applicationPlatform; |
345 | + callback(info); |
346 | + } |
347 | + }, |
348 | + |
349 | + setInputMethodVisible: function(visible, callback) { |
350 | + applicationApiInstance.setInputMethodVisible(visible); |
351 | + if (callback && typeof(callback) === 'function') |
352 | + callback(); |
353 | + }, |
354 | + getInputMethodName: function(callback) { |
355 | + if (callback && typeof(callback) === 'function') |
356 | + callback(applicationApiInstance.getInputMethodName()); |
357 | + }, |
358 | + onInputMethodVisibilityChanged: function(callback) { |
359 | + if (callback && typeof(callback) === 'function') |
360 | + Qt.inputMethod.onVisibleChanged.connect(function() { |
361 | + callback(Qt.inputMethod.visible) |
362 | + }); |
363 | + }, |
364 | + |
365 | + onAboutToQuit: function(callback) { |
366 | + if (callback && typeof(callback) === 'function') |
367 | + applicationApiInstance.applicationAboutToQuit.connect(function(killed) { |
368 | + callback(killed); |
369 | + }); |
370 | + }, |
371 | + |
372 | + setupUriHandler: function(callback) { |
373 | + if (callback && typeof(callback) === 'function') |
374 | + var urihandler = ComponentsBridge.UriHandler; |
375 | + urihandler.opened.connect(function(uris, data) { |
376 | + var translatedUris = [] |
377 | + for (var idx in uris) { |
378 | + translatedUris.push(uris[idx]) |
379 | + } |
380 | + callback(translatedUris); |
381 | + }); |
382 | + }, |
383 | + |
384 | + onDeactivated: function(callback) { |
385 | + if (callback && typeof(callback) === 'function') |
386 | + applicationApiInstance.applicationDeactivated.connect(callback); |
387 | + }, |
388 | + |
389 | + onActivated: function(callback) { |
390 | + if (callback && typeof(callback) === 'function') |
391 | + applicationApiInstance.applicationActivated.connect(callback); |
392 | + }, |
393 | + |
394 | + getScreenOrientation: function(callback) { |
395 | + if (callback && typeof(callback) === 'function') |
396 | + callback(applicationApiInstance.screenOrientation); |
397 | + }, |
398 | + onScreenOrientationChanged: function(callback) { |
399 | + if (callback && typeof(callback) === 'function') |
400 | + applicationApiInstance.applicationScreenOrientationChanged.connect(callback); |
401 | + }, |
402 | + }; |
403 | + |
404 | + function _constructorFromName(className) { |
405 | + var constructorPerName = { |
406 | + "Application": Application, |
407 | + }; |
408 | + return className in constructorPerName |
409 | + ? constructorPerName[className] |
410 | + : null; |
411 | + } |
412 | + |
413 | + return { |
414 | + getApplication: function(callback) { |
415 | + var application = new Application(); |
416 | + callback(application.serialize()); |
417 | + }, |
418 | + |
419 | + // Internal |
420 | + |
421 | + dispatchToObject: function(infos) { |
422 | + var args = infos.args; |
423 | + var callback = infos.callback; |
424 | + var method_name = infos.method_name; |
425 | + var objectid = infos.objectid; |
426 | + var class_name = infos.class_name; |
427 | + |
428 | + if (callback) |
429 | + args.push(callback); |
430 | + |
431 | + var Constructor = _constructorFromName(class_name); |
432 | + |
433 | + var instance = new Constructor(objectid); |
434 | + |
435 | + instance[method_name].apply(instance, args); |
436 | + } |
437 | + }; |
438 | +} |
439 | |
440 | === added directory 'src/Ubuntu/UnityWebApps/bindings/runtime-api/client' |
441 | === added file 'src/Ubuntu/UnityWebApps/bindings/runtime-api/client/runtime-api.js' |
442 | --- src/Ubuntu/UnityWebApps/bindings/runtime-api/client/runtime-api.js 1970-01-01 00:00:00 +0000 |
443 | +++ src/Ubuntu/UnityWebApps/bindings/runtime-api/client/runtime-api.js 2014-03-26 15:53:02 +0000 |
444 | @@ -0,0 +1,256 @@ |
445 | +/* |
446 | + * Copyright 2014 Canonical Ltd. |
447 | + * |
448 | + * This file is part of unity-webapps-qml. |
449 | + * |
450 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
451 | + * it under the terms of the GNU General Public License as published by |
452 | + * the Free Software Foundation; version 3. |
453 | + * |
454 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
455 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
456 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
457 | + * GNU General Public License for more details. |
458 | + * |
459 | + * You should have received a copy of the GNU General Public License |
460 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
461 | + */ |
462 | + |
463 | + |
464 | +/** |
465 | + * RuntimeApi gives access to the application runtime information and management. |
466 | + |
467 | + * @module RuntimeApi |
468 | + */ |
469 | +function createRuntimeApi(backendBridge) { |
470 | + var PLUGIN_URI = 'RuntimeApi'; |
471 | + |
472 | + function Application(id, content) { |
473 | + this._proxy = backendBridge.createRemoteObject( |
474 | + PLUGIN_URI, 'Application', id); |
475 | + |
476 | + this._name = content.name; |
477 | + this._platform = content.platform; |
478 | + this._writableLocation = content.writableLocation; |
479 | + this._screenOrientation = content.screenOrientation; |
480 | + }; |
481 | + Application.prototype = { |
482 | + |
483 | + /** |
484 | + * Retrieves the application name. |
485 | + * |
486 | + * @method getApplicationName |
487 | + * @return {String} application name |
488 | + */ |
489 | + getApplicationName: function() { |
490 | + return this._name; |
491 | + }, |
492 | + |
493 | + /** |
494 | + * Sets up a callback that is to be called when the application's name changed. |
495 | + * |
496 | + * @method onApplicationNameChanged |
497 | + * @param callback {Function(String)} Function to be called when the application's name has changed. |
498 | + */ |
499 | + onApplicationNameChanged: function(callback) { |
500 | + var self = this; |
501 | + this._proxy.call('onApplicationNameChanged' |
502 | + , [function(name) {self._name = name; callback(name); }]); |
503 | + }, |
504 | + |
505 | + /** |
506 | + * Retrieves the fileystem location where the application is allowed to write its data in. |
507 | + * |
508 | + * @method getApplicationWritableLocation |
509 | + * @return {String} application writable location path |
510 | + */ |
511 | + getApplicationWritableLocation: function() { |
512 | + return this._writableLocation; |
513 | + }, |
514 | + |
515 | + /** |
516 | + * Retrieves current platform information. |
517 | + * |
518 | + * @method getPlatformInfos |
519 | + * @return {Object} platform information as a dictionary with the following keys: |
520 | + * - name: the platform name |
521 | + */ |
522 | + getPlatformInfo: function() { |
523 | + return this._platform; |
524 | + }, |
525 | + |
526 | + /** |
527 | + * Sets up a callback that is to be called when the application is about to quit. |
528 | + * |
529 | + * @method onAboutToQuit |
530 | + * @param callback {Function()} Function to be called when the application is about to quit. |
531 | + */ |
532 | + onAboutToQuit: function(callback) { |
533 | + this._proxy.call('onAboutToQuit' |
534 | + , [callback]); |
535 | + }, |
536 | + |
537 | + /** |
538 | + * Sets up a callback that is to be called when the application has been deactivated (background). |
539 | + * |
540 | + * @method onDeactivated |
541 | + * @param callback {Function()} Function to be called when the application has been deactivated. |
542 | + */ |
543 | + onDeactivated: function(callback) { |
544 | + this._proxy.call('onDeactivated' |
545 | + , [callback]); |
546 | + }, |
547 | + |
548 | + /** |
549 | + * Sets up a callback that is to be called when the application has been activated (from background). |
550 | + * |
551 | + * @method onActivated |
552 | + * @param callback {Function()} Function to be called when the application has been activated. |
553 | + */ |
554 | + onActivated: function(callback) { |
555 | + this._proxy.call('onActivated' |
556 | + , [callback]); |
557 | + }, |
558 | + |
559 | + /** |
560 | + * Retrieves the current screen orientation. |
561 | + * |
562 | + * @method getScreenOrientation |
563 | + * @return {ScreenOrientation} current screen orientation. |
564 | + */ |
565 | + getScreenOrientation: function() { |
566 | + return this._screenOrientation; |
567 | + }, |
568 | + |
569 | + /** |
570 | + * Sets up a callback that is to be called when the application's screen has changed its orientation. |
571 | + * |
572 | + * @method onScreenOrientationChanged |
573 | + * @param callback {Function(ScreenOrientation)} Function to be called when the application's screen orientation has changed. |
574 | + */ |
575 | + onScreenOrientationChanged: function(callback) { |
576 | + var self = this; |
577 | + this._proxy.call('onScreenOrientationChanged' |
578 | + , [function(orientation) {self._screenOrientation = orientation; callback(orientation); }]); |
579 | + }, |
580 | + |
581 | + /** |
582 | + * Sets up a URI handler. The application can be sent URIs to open. |
583 | + * |
584 | + * @method setupUriHandler |
585 | + * @param callback {Function([String])} Function to be called with the current list of uris to open |
586 | + */ |
587 | + setupUriHandler: function(callback) { |
588 | + this._proxy.call('setupUriHandler' |
589 | + , [callback]); |
590 | + }, |
591 | + |
592 | + /** |
593 | + * Retrieves the current input method's name. The name varies depending on the platform |
594 | + * e.g. maliit can be part of the name for a maliit based Virtual Keyboard (possibly mangled |
595 | + * with e.g. 'phablet'), when a keyboard is there the name can be empty, ... |
596 | + * |
597 | + * @method getInputMethodName |
598 | + * @param callback {Function(String)} Function to be called with the current input method name |
599 | + */ |
600 | + getInputMethodName: function(callback) { |
601 | + this._proxy.call('getInputMethodName' |
602 | + , [] |
603 | + , callback); |
604 | + }, |
605 | + |
606 | + /** |
607 | + * Sets up a callback that is to be called when the On Screen Keyboard visibility has changed. |
608 | + * |
609 | + * @method onInputMethodVisibilityChanged |
610 | + * @param callback {Function(Bool)} Function to be called when the On Screen Keyboard visibility has changed (received the visibility as an arg). |
611 | + */ |
612 | + onInputMethodVisibilityChanged: function(callback) { |
613 | + this._proxy.call('onInputMethodVisibilityChanged' |
614 | + , [callback]); |
615 | + } |
616 | + }; |
617 | + |
618 | + function _constructorFromName(className) { |
619 | + var constructorPerName = { |
620 | + "Application": Application, |
621 | + }; |
622 | + return className in constructorPerName |
623 | + ? constructorPerName[className] |
624 | + : null; |
625 | + }; |
626 | + |
627 | + |
628 | +/** |
629 | + * The RuntimeApi object |
630 | + |
631 | + * @class RuntimeApi |
632 | + * @constructor |
633 | + * @example |
634 | + |
635 | + var api = external.getUnityObject('1.0'); |
636 | + api.RuntimeApi.getApplication(function(application) { |
637 | + console.log('Application name: ' + application.getApplicationName()); |
638 | + }); |
639 | + */ |
640 | + return { |
641 | + /** |
642 | + Enumeration of the available types of ScreenOrientation. |
643 | + |
644 | + Values: |
645 | + |
646 | + Landscape: The application screen is in landscape mode |
647 | + |
648 | + InvertedLandscape: The application screen is in inverted landscape mode |
649 | + |
650 | + Portrait: The application screen is in portrait mode |
651 | + |
652 | + InvertedPortrait: The application screen is in inverted portrait mode |
653 | + |
654 | + Unknown: The application screen is in an unknown mode |
655 | + |
656 | + @static |
657 | + @property ScreenOrientation {Object} |
658 | + |
659 | + @example |
660 | + |
661 | + var api = external.getUnityObject('1.0'); |
662 | + var orientation = api.RuntimeApi.ScreenOrientation; |
663 | + // use orientation.Landscape or orientation.Portrait |
664 | + */ |
665 | + ScreenOrientation: { |
666 | + Landscape: "Landscape", |
667 | + |
668 | + InvertedLandscape: "InvertedLandscape", |
669 | + |
670 | + Portrait: "Portrait", |
671 | + |
672 | + InvertedPortrait: "InvertedPortrait", |
673 | + |
674 | + Unknwon: "Unknown", |
675 | + }, |
676 | + |
677 | + /** |
678 | + * Creates an Application object. |
679 | + * |
680 | + * @method getApplication |
681 | + * @param callback {Function (Application)} |
682 | + */ |
683 | + getApplication: function(callback) { |
684 | + backendBridge.call('RuntimeApi.getApplication' |
685 | + , [] |
686 | + , callback); |
687 | + }, |
688 | + |
689 | + /** |
690 | + * @private |
691 | + * |
692 | + */ |
693 | + createObjectWrapper: function(objectType, objectId, content) { |
694 | + var Constructor = _constructorFromName(objectType); |
695 | + return new Constructor(objectId, content); |
696 | + }, |
697 | + }; |
698 | +}; |
699 | + |
700 | + |
701 | |
702 | === added file 'src/Ubuntu/UnityWebApps/plugin/application-api.cpp' |
703 | --- src/Ubuntu/UnityWebApps/plugin/application-api.cpp 1970-01-01 00:00:00 +0000 |
704 | +++ src/Ubuntu/UnityWebApps/plugin/application-api.cpp 2014-03-26 15:53:02 +0000 |
705 | @@ -0,0 +1,287 @@ |
706 | +/* |
707 | + * Copyright 2014 Canonical Ltd. |
708 | + * |
709 | + * This file is part of unity-webapps-qml. |
710 | + * |
711 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
712 | + * it under the terms of the GNU General Public License as published by |
713 | + * the Free Software Foundation; version 3. |
714 | + * |
715 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
716 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
717 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
718 | + * GNU General Public License for more details. |
719 | + * |
720 | + * You should have received a copy of the GNU General Public License |
721 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
722 | + */ |
723 | + |
724 | +#include "application-api.h" |
725 | + |
726 | +#include "application-signal-to-qt-bridge.h" |
727 | + |
728 | +#include <QDebug> |
729 | +#include <QGuiApplication> |
730 | +#include <QScreen> |
731 | +#include <QDir> |
732 | +#include <QtCore/QCoreApplication> |
733 | +#include <QtCore/QStandardPaths> |
734 | +#include <signal.h> |
735 | + |
736 | + |
737 | +namespace |
738 | +{ |
739 | + |
740 | +QString |
741 | +nameFromScreenOrientation (Qt::ScreenOrientation orientation) |
742 | +{ |
743 | + switch (orientation) |
744 | + { |
745 | + case Qt::InvertedLandscapeOrientation: |
746 | + return QString("InvertedLandscape"); |
747 | + |
748 | + case Qt::LandscapeOrientation: |
749 | + return QString("Landscape"); |
750 | + |
751 | + case Qt::PortraitOrientation: |
752 | + return QString("Portrait"); |
753 | + |
754 | + case Qt::InvertedPortraitOrientation: |
755 | + return QString("InvertedPortrait"); |
756 | + |
757 | + case Qt::PrimaryOrientation: |
758 | + return QString("Primary"); |
759 | + |
760 | + default: |
761 | + break; |
762 | + } |
763 | + |
764 | + return QString("Unknown"); |
765 | +} |
766 | + |
767 | +} |
768 | + |
769 | +class ApplicationApiEventListener : public QObject |
770 | +{ |
771 | + Q_OBJECT |
772 | + |
773 | +public: |
774 | + ApplicationApiEventListener(QObject * parent) |
775 | + : QObject(parent) |
776 | + { |
777 | + if (QGuiApplication::instance()) |
778 | + QGuiApplication::instance()->installEventFilter(this); |
779 | + } |
780 | + ~ApplicationApiEventListener() |
781 | + { |
782 | + if (QGuiApplication::instance()) |
783 | + QGuiApplication::instance()->removeEventFilter(this); |
784 | + } |
785 | + |
786 | + bool eventFilter(QObject *obj, |
787 | + QEvent *event) |
788 | + { |
789 | + switch (event->type()) |
790 | + { |
791 | + case QEvent::ApplicationActivate: |
792 | + Q_EMIT activated(); |
793 | + break; |
794 | + case QEvent::ApplicationDeactivate: |
795 | + Q_EMIT deactivated(); |
796 | + break; |
797 | + default: |
798 | + break; |
799 | + } |
800 | + return QObject::eventFilter(obj, event); |
801 | + } |
802 | + |
803 | +Q_SIGNALS: |
804 | + |
805 | + void activated(); |
806 | + void deactivated(); |
807 | +}; |
808 | + |
809 | + |
810 | +class ApplicationApiPrivate: public QObject |
811 | +{ |
812 | + Q_OBJECT |
813 | + |
814 | +public: |
815 | + ApplicationApiPrivate(QObject * parent) |
816 | + : QObject(parent), |
817 | + _applicationEventListener(new ApplicationApiEventListener(this)), |
818 | + _applicationSignalBridge(new ApplicationSignalToQtBridge(this)) |
819 | + {} |
820 | + ~ApplicationApiPrivate() |
821 | + { |
822 | + delete _applicationEventListener; |
823 | + delete _applicationSignalBridge; |
824 | + } |
825 | + |
826 | + ApplicationApiEventListener * _applicationEventListener; |
827 | + ApplicationSignalToQtBridge * _applicationSignalBridge; |
828 | +}; |
829 | + |
830 | + |
831 | +ApplicationApi::ApplicationApi(QObject *parent) : |
832 | + QObject(parent), |
833 | + d_ptr(new ApplicationApiPrivate(this)) |
834 | + |
835 | +{ |
836 | + Q_D(ApplicationApi); |
837 | + |
838 | + QObject::connect(QCoreApplication::instance(), |
839 | + &QCoreApplication::aboutToQuit, |
840 | + this, |
841 | + &ApplicationApi::aboutToQuit); |
842 | + |
843 | + QObject::connect(d->_applicationEventListener, |
844 | + &ApplicationApiEventListener::activated, |
845 | + this, |
846 | + &ApplicationApi::activated); |
847 | + |
848 | + QObject::connect(d->_applicationEventListener, |
849 | + &ApplicationApiEventListener::deactivated, |
850 | + this, |
851 | + &ApplicationApi::deactivated); |
852 | + |
853 | + QObject::connect(d->_applicationSignalBridge, |
854 | + &ApplicationSignalToQtBridge::onSignalRaised, |
855 | + this, |
856 | + &ApplicationApi::signalReceived); |
857 | + |
858 | + // We explictly handle the SIGTERM signal case that is being sent |
859 | + // on Touch to an application being killed by the platform. |
860 | + // Upstart sends this signal when the application is closed from app scope. |
861 | + d->_applicationSignalBridge->addSignalHandlerFor(SIGTERM); |
862 | + |
863 | + QScreen * screen = QGuiApplication::primaryScreen(); |
864 | + if (screen) |
865 | + { |
866 | + QObject::connect(screen, |
867 | + &QScreen::orientationChanged, |
868 | + this, |
869 | + &ApplicationApi::screenOrientationChanged); |
870 | + } |
871 | +} |
872 | + |
873 | +ApplicationApi::~ApplicationApi() |
874 | +{ |
875 | + Q_D(ApplicationApi); |
876 | + |
877 | + QObject::disconnect(QCoreApplication::instance(), |
878 | + &QCoreApplication::aboutToQuit, |
879 | + this, |
880 | + &ApplicationApi::aboutToQuit); |
881 | + |
882 | + QObject::disconnect(d->_applicationEventListener, |
883 | + &ApplicationApiEventListener::activated, |
884 | + this, |
885 | + &ApplicationApi::activated); |
886 | + |
887 | + QObject::disconnect(d->_applicationEventListener, |
888 | + &ApplicationApiEventListener::deactivated, |
889 | + this, |
890 | + &ApplicationApi::deactivated); |
891 | + |
892 | + QObject::disconnect(d->_applicationSignalBridge, |
893 | + &ApplicationSignalToQtBridge::onSignalRaised, |
894 | + this, |
895 | + &ApplicationApi::signalReceived); |
896 | + |
897 | + QScreen * screen = QGuiApplication::primaryScreen(); |
898 | + if (screen) |
899 | + { |
900 | + QObject::disconnect(screen, |
901 | + &QScreen::orientationChanged, |
902 | + this, |
903 | + &ApplicationApi::screenOrientationChanged); |
904 | + } |
905 | + |
906 | + delete d_ptr; |
907 | +} |
908 | + |
909 | +QString ApplicationApi::getApplicationName() const |
910 | +{ |
911 | + if ( ! qgetenv("APP_ID").isEmpty()) |
912 | + return qgetenv("APP_ID"); |
913 | + |
914 | + return QCoreApplication::applicationName(); |
915 | +} |
916 | + |
917 | +QString ApplicationApi::getApplicationDataPath() const |
918 | +{ |
919 | + QDir dataLocation( |
920 | + QStandardPaths::writableLocation( |
921 | + QStandardPaths::DataLocation)); |
922 | + |
923 | + if (!dataLocation.exists()) { |
924 | + QDir::root().mkpath(dataLocation.absolutePath()); |
925 | + } |
926 | + |
927 | + return dataLocation.absolutePath(); |
928 | +} |
929 | + |
930 | +QString ApplicationApi::getApplicationScreenOrientation() const |
931 | +{ |
932 | + QScreen * screen = QGuiApplication::primaryScreen(); |
933 | + |
934 | + return nameFromScreenOrientation(screen->primaryOrientation()); |
935 | +} |
936 | + |
937 | +QString ApplicationApi::getInputMethodName() const |
938 | +{ |
939 | + return QString(getenv("QT_IM_MODULE")); |
940 | +} |
941 | + |
942 | +void ApplicationApi::setInputMethodVisible(bool visible) |
943 | +{ |
944 | + QGuiApplication::inputMethod()->setVisible(visible); |
945 | + if (visible) |
946 | + QGuiApplication::inputMethod()->show(); |
947 | + else |
948 | + QGuiApplication::inputMethod()->hide(); |
949 | +} |
950 | + |
951 | +QString ApplicationApi::getApplicationPlatform() const |
952 | +{ |
953 | + return QGuiApplication::platformName(); |
954 | +} |
955 | + |
956 | +void ApplicationApi::aboutToQuit() |
957 | +{ |
958 | + Q_EMIT applicationAboutToQuit(false); |
959 | +} |
960 | + |
961 | +void ApplicationApi::activated() |
962 | +{ |
963 | + Q_EMIT applicationActivated(); |
964 | +} |
965 | + |
966 | +void ApplicationApi::deactivated() |
967 | +{ |
968 | + Q_EMIT applicationDeactivated(); |
969 | +} |
970 | + |
971 | +void ApplicationApi::signalReceived(int type) |
972 | +{ |
973 | + if (type != SIGTERM && type != SIGINT) |
974 | + return; |
975 | + |
976 | + bool killed = (type == SIGTERM); |
977 | + |
978 | + Q_EMIT applicationAboutToQuit(killed); |
979 | + |
980 | + QCoreApplication::quit(); |
981 | +} |
982 | + |
983 | +void ApplicationApi::screenOrientationChanged(Qt::ScreenOrientation orientation) |
984 | +{ |
985 | + Q_EMIT applicationScreenOrientationChanged( |
986 | + nameFromScreenOrientation( |
987 | + orientation)); |
988 | +} |
989 | + |
990 | + |
991 | +#include "application-api.moc" |
992 | + |
993 | |
994 | === added file 'src/Ubuntu/UnityWebApps/plugin/application-api.h' |
995 | --- src/Ubuntu/UnityWebApps/plugin/application-api.h 1970-01-01 00:00:00 +0000 |
996 | +++ src/Ubuntu/UnityWebApps/plugin/application-api.h 2014-03-26 15:53:02 +0000 |
997 | @@ -0,0 +1,75 @@ |
998 | +/* |
999 | + * Copyright 2014 Canonical Ltd. |
1000 | + * |
1001 | + * This file is part of unity-webapps-qml. |
1002 | + * |
1003 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
1004 | + * it under the terms of the GNU General Public License as published by |
1005 | + * the Free Software Foundation; version 3. |
1006 | + * |
1007 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
1008 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1009 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1010 | + * GNU General Public License for more details. |
1011 | + * |
1012 | + * You should have received a copy of the GNU General Public License |
1013 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1014 | + */ |
1015 | + |
1016 | +#ifndef UNITY_WEBAPPS_APPLICATIONAPI_H |
1017 | +#define UNITY_WEBAPPS_APPLICATIONAPI_H |
1018 | + |
1019 | +#include <QObject> |
1020 | + |
1021 | +class ApplicationApiPrivate; |
1022 | + |
1023 | +class ApplicationApi : public QObject |
1024 | +{ |
1025 | + Q_OBJECT |
1026 | + Q_PROPERTY(QString applicationName READ getApplicationName NOTIFY applicationNameChanged) |
1027 | + Q_PROPERTY(QString screenOrientation READ getApplicationScreenOrientation NOTIFY applicationScreenOrientationChanged) |
1028 | + Q_PROPERTY(QString applicationDataPath READ getApplicationDataPath) |
1029 | + Q_PROPERTY(QString applicationPlatform READ getApplicationPlatform) |
1030 | + |
1031 | + |
1032 | +public: |
1033 | + explicit ApplicationApi(QObject *parent = 0); |
1034 | + ~ApplicationApi(); |
1035 | + |
1036 | + QString getApplicationName() const; |
1037 | + |
1038 | + QString getApplicationDataPath() const; |
1039 | + |
1040 | + QString getApplicationPlatform() const; |
1041 | + |
1042 | + QString getApplicationScreenOrientation() const; |
1043 | + |
1044 | + Q_INVOKABLE QString getInputMethodName() const; |
1045 | + Q_INVOKABLE void setInputMethodVisible(bool); |
1046 | + |
1047 | + |
1048 | +Q_SIGNALS: |
1049 | + |
1050 | + void applicationNameChanged(); |
1051 | + void applicationAboutToQuit(bool killed); |
1052 | + void applicationDeactivated(); |
1053 | + void applicationActivated(); |
1054 | + void applicationScreenOrientationChanged(QString); |
1055 | + |
1056 | + |
1057 | +public Q_SLOTS: |
1058 | + |
1059 | + void aboutToQuit(); |
1060 | + void deactivated(); |
1061 | + void activated(); |
1062 | + void screenOrientationChanged(Qt::ScreenOrientation); |
1063 | + void signalReceived(int type); |
1064 | + |
1065 | + |
1066 | +private: |
1067 | + |
1068 | + ApplicationApiPrivate *d_ptr; |
1069 | + Q_DECLARE_PRIVATE(ApplicationApi) |
1070 | +}; |
1071 | + |
1072 | +#endif // UNITY_WEBAPPS_APPLICATIONAPI_H |
1073 | |
1074 | === added file 'src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.cpp' |
1075 | --- src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.cpp 1970-01-01 00:00:00 +0000 |
1076 | +++ src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.cpp 2014-03-26 15:53:02 +0000 |
1077 | @@ -0,0 +1,139 @@ |
1078 | +/* |
1079 | + * Copyright 2014 Canonical Ltd. |
1080 | + * |
1081 | + * This file is part of unity-webapps-qml. |
1082 | + * |
1083 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
1084 | + * it under the terms of the GNU General Public License as published by |
1085 | + * the Free Software Foundation; version 3. |
1086 | + * |
1087 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
1088 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1089 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1090 | + * GNU General Public License for more details. |
1091 | + * |
1092 | + * You should have received a copy of the GNU General Public License |
1093 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1094 | + */ |
1095 | + |
1096 | +#include "application-signal-to-qt-bridge.h" |
1097 | + |
1098 | +#include <QDebug> |
1099 | +#include <QSocketNotifier> |
1100 | + |
1101 | +#include <sys/socket.h> |
1102 | +#include <signal.h> |
1103 | +#include <unistd.h> |
1104 | + |
1105 | +/** |
1106 | + * @brief The ApplicationSignalToQtBridgePrivate class |
1107 | + * |
1108 | + * It does the job described here: |
1109 | + * |
1110 | + * https://qt-project.org/doc/qt-5.0/qtdoc/unix-signals.html |
1111 | + * |
1112 | + * and bridges Unix signal handlers & qt objects in a proper |
1113 | + * way. |
1114 | + * |
1115 | + */ |
1116 | + |
1117 | +class ApplicationSignalToQtBridgePrivate: public QObject |
1118 | +{ |
1119 | + Q_OBJECT |
1120 | + |
1121 | +public: |
1122 | + ApplicationSignalToQtBridgePrivate(QObject * parent) |
1123 | + : QObject(parent), |
1124 | + _signalSocketNotifier(NULL) |
1125 | + {} |
1126 | + ~ApplicationSignalToQtBridgePrivate() |
1127 | + { |
1128 | + delete _signalSocketNotifier; |
1129 | + } |
1130 | + |
1131 | + QSocketNotifier * _signalSocketNotifier; |
1132 | +}; |
1133 | + |
1134 | + |
1135 | +int ApplicationSignalToQtBridge::signalSocketPair[2]; |
1136 | + |
1137 | +ApplicationSignalToQtBridge::ApplicationSignalToQtBridge(QObject *parent) |
1138 | + : QObject(parent) |
1139 | + , d_ptr(new ApplicationSignalToQtBridgePrivate(this)) |
1140 | +{} |
1141 | + |
1142 | +ApplicationSignalToQtBridge::~ApplicationSignalToQtBridge() |
1143 | +{ |
1144 | + delete d_ptr; |
1145 | +} |
1146 | + |
1147 | +void ApplicationSignalToQtBridge::setupQtSignalListener() |
1148 | +{ |
1149 | + Q_D(ApplicationSignalToQtBridge); |
1150 | + |
1151 | + if (0 != ::socketpair(AF_UNIX, SOCK_STREAM, 0, signalSocketPair)) |
1152 | + { |
1153 | + qFatal("Couldn't create HUP socketpair"); |
1154 | + } |
1155 | + |
1156 | + d->_signalSocketNotifier = |
1157 | + new QSocketNotifier (signalSocketPair[1], |
1158 | + QSocketNotifier::Read, |
1159 | + this); |
1160 | + |
1161 | + connect(d->_signalSocketNotifier, |
1162 | + SIGNAL(activated(int)), |
1163 | + this, |
1164 | + SLOT(handleSignal(int))); |
1165 | +} |
1166 | + |
1167 | +bool ApplicationSignalToQtBridge::addSignalHandlerFor(int type) |
1168 | +{ |
1169 | + Q_D(ApplicationSignalToQtBridge); |
1170 | + |
1171 | + if ( ! d->_signalSocketNotifier) |
1172 | + setupQtSignalListener(); |
1173 | + |
1174 | + struct sigaction sa; |
1175 | + |
1176 | + sa.sa_handler = ApplicationSignalToQtBridge::signalHandler; |
1177 | + sigemptyset (&sa.sa_mask); |
1178 | + sa.sa_flags = 0; |
1179 | + sa.sa_flags |= SA_RESTART; |
1180 | + |
1181 | + return sigaction (type, &sa, 0) > 0; |
1182 | +} |
1183 | + |
1184 | +void ApplicationSignalToQtBridge::signalHandler(int type) |
1185 | +{ |
1186 | + if (0 != signalSocketPair[0]) |
1187 | + { |
1188 | + size_t size = |
1189 | + ::write (signalSocketPair[0], |
1190 | + &type, |
1191 | + sizeof(type)); |
1192 | + Q_UNUSED(size); |
1193 | + } |
1194 | +} |
1195 | + |
1196 | +void ApplicationSignalToQtBridge::handleSignal(int socket) |
1197 | +{ |
1198 | + Q_D(ApplicationSignalToQtBridge); |
1199 | + |
1200 | + Q_UNUSED(socket); |
1201 | + |
1202 | + d->_signalSocketNotifier->setEnabled(false); |
1203 | + |
1204 | + int type = 0; |
1205 | + size_t size = |
1206 | + ::read (signalSocketPair[1], &type, sizeof(type)); |
1207 | + Q_UNUSED(size); |
1208 | + |
1209 | + Q_EMIT onSignalRaised(type); |
1210 | + |
1211 | + d->_signalSocketNotifier->setEnabled(true); |
1212 | +} |
1213 | + |
1214 | + |
1215 | +#include "application-signal-to-qt-bridge.moc" |
1216 | + |
1217 | |
1218 | === added file 'src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.h' |
1219 | --- src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.h 1970-01-01 00:00:00 +0000 |
1220 | +++ src/Ubuntu/UnityWebApps/plugin/application-signal-to-qt-bridge.h 2014-03-26 15:53:02 +0000 |
1221 | @@ -0,0 +1,62 @@ |
1222 | +/* |
1223 | + * Copyright 2014 Canonical Ltd. |
1224 | + * |
1225 | + * This file is part of unity-webapps-qml. |
1226 | + * |
1227 | + * unity-webapps-qml is free software; you can redistribute it and/or modify |
1228 | + * it under the terms of the GNU General Public License as published by |
1229 | + * the Free Software Foundation; version 3. |
1230 | + * |
1231 | + * unity-webapps-qml is distributed in the hope that it will be useful, |
1232 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1233 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1234 | + * GNU General Public License for more details. |
1235 | + * |
1236 | + * You should have received a copy of the GNU General Public License |
1237 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1238 | + */ |
1239 | + |
1240 | +#ifndef APPLICATIONSIGNALTOQTBRIDGE_H |
1241 | +#define APPLICATIONSIGNALTOQTBRIDGE_H |
1242 | + |
1243 | +#include <QObject> |
1244 | + |
1245 | + |
1246 | +class ApplicationSignalToQtBridgePrivate; |
1247 | + |
1248 | +class ApplicationSignalToQtBridge : public QObject |
1249 | +{ |
1250 | + Q_OBJECT |
1251 | + |
1252 | +public: |
1253 | + |
1254 | + explicit ApplicationSignalToQtBridge (QObject *parent = 0); |
1255 | + ~ApplicationSignalToQtBridge (); |
1256 | + |
1257 | + bool addSignalHandlerFor(int type); |
1258 | + |
1259 | + |
1260 | +public Q_SLOTS: |
1261 | + |
1262 | + void handleSignal(int type); |
1263 | + |
1264 | + |
1265 | +Q_SIGNALS: |
1266 | + |
1267 | + void onSignalRaised(int type); |
1268 | + |
1269 | + |
1270 | +private: |
1271 | + |
1272 | + void setupQtSignalListener(); |
1273 | + |
1274 | + // Unix signal handlers. |
1275 | + static void signalHandler(int type); |
1276 | + |
1277 | + static int signalSocketPair[2]; |
1278 | + |
1279 | + ApplicationSignalToQtBridgePrivate *d_ptr; |
1280 | + Q_DECLARE_PRIVATE(ApplicationSignalToQtBridge) |
1281 | +}; |
1282 | + |
1283 | +#endif // APPLICATIONSIGNALTOQTBRIDGE_H |
1284 | |
1285 | === modified file 'src/Ubuntu/UnityWebApps/plugin/plugin.pro' |
1286 | --- src/Ubuntu/UnityWebApps/plugin/plugin.pro 2014-01-17 15:51:27 +0000 |
1287 | +++ src/Ubuntu/UnityWebApps/plugin/plugin.pro 2014-03-26 15:53:02 +0000 |
1288 | @@ -40,7 +40,9 @@ |
1289 | unity-webapps-desktop-infos.cpp \ |
1290 | unity-webapps-icon-utils.cpp \ |
1291 | callback.cpp \ |
1292 | - abstract-item-model-adaptor.cpp |
1293 | + abstract-item-model-adaptor.cpp \ |
1294 | + application-api.cpp \ |
1295 | + application-signal-to-qt-bridge.cpp |
1296 | |
1297 | HEADERS += \ |
1298 | qml-plugin.h \ |
1299 | @@ -57,7 +59,9 @@ |
1300 | unity-webapps-desktop-infos.h \ |
1301 | unity-webapps-icon-utils.h \ |
1302 | callback.h \ |
1303 | - abstract-item-model-adaptor.h |
1304 | + abstract-item-model-adaptor.h \ |
1305 | + application-api.h \ |
1306 | + application-signal-to-qt-bridge.h |
1307 | |
1308 | DEFINES += \ |
1309 | API_URI=\\\"$${API_URI}\\\" |
1310 | |
1311 | === modified file 'src/Ubuntu/UnityWebApps/plugin/qml-plugin.cpp' |
1312 | --- src/Ubuntu/UnityWebApps/plugin/qml-plugin.cpp 2014-01-17 15:51:27 +0000 |
1313 | +++ src/Ubuntu/UnityWebApps/plugin/qml-plugin.cpp 2014-03-26 15:53:02 +0000 |
1314 | @@ -17,6 +17,10 @@ |
1315 | */ |
1316 | |
1317 | #include "qml-plugin.h" |
1318 | + |
1319 | +#include <QtQml/QQmlEngine> |
1320 | +#include <QtQml/QQmlContext> |
1321 | + |
1322 | #include "unity-webapps-api.h" |
1323 | #include "unity-webapps-api-notifications.h" |
1324 | #include "unity-webapps-api-messaging-menu.h" |
1325 | @@ -26,11 +30,19 @@ |
1326 | #include "unity-webapps-app-model.h" |
1327 | #include "unity-webapps-app-infos.h" |
1328 | |
1329 | +#include "application-api.h" |
1330 | #include "abstract-item-model-adaptor.h" |
1331 | #include "callback.h" |
1332 | |
1333 | #include <qqml.h> |
1334 | |
1335 | +static QObject *createApplicationApi(QQmlEngine *engine, QJSEngine *scriptEngine) |
1336 | +{ |
1337 | + Q_UNUSED(engine); |
1338 | + Q_UNUSED(scriptEngine); |
1339 | + |
1340 | + return new ApplicationApi(); |
1341 | +} |
1342 | |
1343 | void WebappsQmlPlugin::registerTypes(const char *uri) |
1344 | { |
1345 | @@ -49,5 +61,8 @@ |
1346 | |
1347 | // TODO bump version |
1348 | qmlRegisterType<AbstractItemModelAdaptor> (uri, 0, 1, "AbstractItemModelAdaptor"); |
1349 | + |
1350 | + // |
1351 | + qmlRegisterSingletonType<ApplicationApi>(uri, 0, 1, "ApplicationApi", createApplicationApi); |
1352 | } |
1353 | |
1354 | |
1355 | === modified file 'src/Ubuntu/UnityWebApps/unity-webapps-api.js.in' |
1356 | --- src/Ubuntu/UnityWebApps/unity-webapps-api.js.in 2014-03-18 17:26:34 +0000 |
1357 | +++ src/Ubuntu/UnityWebApps/unity-webapps-api.js.in 2014-03-26 15:53:02 +0000 |
1358 | @@ -33,6 +33,7 @@ |
1359 | //@include ./bindings/alarm-api/client/alarm-api.js |
1360 | //@include ./bindings/content-hub/client/content-hub.js |
1361 | //@include ./bindings/online-accounts/client/online-accounts.js |
1362 | + //@include ./bindings/runtime-api/client/runtime-api.js |
1363 | //@include ./common/js/unity-backend-messaging-proxy.js |
1364 | //@include ./common/js/unity-binding-proxy.js |
1365 | //@include ./common/js/unity-binding-bridge.js |
1366 | @@ -280,6 +281,7 @@ |
1367 | OnlineAccounts: createOnlineAccountsApi(backend), |
1368 | AlarmApi: createAlarmApi(backend), |
1369 | ContentHub: createContentHubApi(backend), |
1370 | + RuntimeApi: createRuntimeApi(backend), |
1371 | }; |
1372 | |
1373 | return api; |
1374 | |
1375 | === modified file 'tests/unit/test_plugin/tst_plugin.cpp' |
1376 | --- tests/unit/test_plugin/tst_plugin.cpp 2014-01-21 19:58:04 +0000 |
1377 | +++ tests/unit/test_plugin/tst_plugin.cpp 2014-03-26 15:53:02 +0000 |
1378 | @@ -25,6 +25,8 @@ |
1379 | #include <QSignalSpy> |
1380 | #include <QJsonDocument> |
1381 | #include <QVariantMap> |
1382 | +#include <QProcess> |
1383 | +#include <QProcessEnvironment> |
1384 | |
1385 | #include "plugin/unity-webapps-api.h" |
1386 | #include "plugin/abstract-item-model-adaptor.h" |
1387 | @@ -172,5 +174,22 @@ |
1388 | delete model; |
1389 | } |
1390 | |
1391 | +void PluginTest::testApplicationSignalHandler() |
1392 | +{ |
1393 | + QProcess testApp; |
1394 | + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); |
1395 | + |
1396 | + env.insert("APP_ID", "application-api"); |
1397 | + |
1398 | + testApp.setProcessEnvironment(env); |
1399 | + testApp.start("qmlscene -I ../../../src ../../../examples/api-bindings/application-api/main.qml"); |
1400 | + testApp.waitForStarted(); |
1401 | + |
1402 | + testApp.terminate(); |
1403 | + testApp.waitForFinished(); |
1404 | + |
1405 | + QVERIFY(true); |
1406 | +} |
1407 | + |
1408 | #include "tst_plugin.moc" |
1409 | |
1410 | |
1411 | === modified file 'tests/unit/test_plugin/tst_plugin.h' |
1412 | --- tests/unit/test_plugin/tst_plugin.h 2014-01-17 15:51:27 +0000 |
1413 | +++ tests/unit/test_plugin/tst_plugin.h 2014-03-26 15:53:02 +0000 |
1414 | @@ -35,6 +35,7 @@ |
1415 | void testLoadPlugin(); |
1416 | void testInit(); |
1417 | void testAbstractItemModelAdaptor(); |
1418 | + void testApplicationSignalHandler(); |
1419 | }; |
1420 | |
1421 | #endif // TST_PLUGIN_H |
I tested it and it's mostly working. A few comments:
getPlatformInfos: I think it's better to call it "getPlatformInfo" without the final "s". Anyway, this just returns the name of the QPA plugin, so I'd rather rename the method to "getPlatformName" or keep the current name and make it return a dictionary, currently having only one field "name" which contains the platform name. But I'd take the second approach only if you really plan to add more info there in the future.
The example expects the onActivated() and onDeactivated() signal to carry a parameter, but they don't.
All the methods are asynchronous and take a callback; even the applicationName() function is asynchronous, even if the result is immediately available. I'm not familiar with HTML5 development so this might be perfectly fine, I just point this out because coming from the C++ world this sounds rather strange (and a bit inconvenient).
Naming: it's better to use the same convention for all the getters: either start their name always with a "get", or never. Most of the methods you added start with "get", but "applicationName" doesn't.
getInputMethod(): it's not very clear what this function does; maybe rename it to "getInputMethod Name"?
nameFromScreenO rientation( ): you are only use two possible values, "Landscape" and "Portrait", while Qt supports 4. I guess that most apps don't care about distinguishing between the extra modes, but maybe some do (to be sure that the mic is on a specific side, for instance)?