~unity-team/unity-scopes-api/trunk

64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
1
/*!
163.98.11 by Pawel Stolowski
Mainpage uses notitle.
2
\mainpage notitle
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
3
4
\section overview What are scopes
5
6
\subsection intro Introduction
163.98.4 by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox
7
163.315.1 by Michi Henning
Lots of doc fixes and updates.
8
One of Unity’s core features on the desktop is the Dash. The Dash allows users to search for and discover virtually anything,
9
from local files and applications to web content and other online data. The Dash achieves this by interfacing with one or more
10
search plug-ins called “scopes”, such as “Apps”, “Music”, “Videos”, “Amazon”, “Wikipedia”, and “Youtube”.
163.98.4 by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox
11
12
On the phone and tablet, scopes make up the central user interface, as they provide everything a user needs from an operating
13
system. Scopes enable users to locate and launch applications, access local files, play music and videos, search the web,
14
manage their favourite social network, keep up with the latest news, and much more.
15
163.315.1 by Michi Henning
Lots of doc fixes and updates.
16
Each scope is a dedicated search engine for the category of data it represents. The data source could be a local database,
17
a web service, or even an aggregation of other scopes. (For example, the “Music” scope aggregates “Local Music” and “Online Music”
18
scopes). A scope is responsible for performing the actual search and returning the best possible results for each
163.98.4 by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox
19
query it receives.
20
163.315.1 by Michi Henning
Lots of doc fixes and updates.
21
This document describes how to implement, test, and package your own scope using the Unity Scopes C++ API (unity-scopes-api).
163.98.4 by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox
22
163.146.1 by Pete Woods
Convert the remote scopes section to a conditional section
23
\if RemoteScopes
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
24
\subsection LvsR Local vs remote scopes
163.98.4 by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox
25
26
Local scopes are scopes that are located and run on the user’s device, while remote scopes (or “Smart Scopes”) are scopes that
27
are located and run remotely on the Ubuntu Smart Scopes Server (or “SSS”). (Note: Although local scopes execute as local
28
processes, they may still query online services in order to retrieve search results). A local scope usually requires local data,
29
and therefore, can only be run locally, while a remote scope can effectively be run both locally and remotely.
30
31
When deciding on whether to write a local or remote scope, keep the user’s privacy in mind. For security reasons, a scope should
32
not access the user’s personal data unless absolutely necessary (i.e. The scope requires account information or local data to
33
perform searches). It is only in these situations that a scope should be written to run locally. <b>By default, a scope should
163.98.13 by Pawel Stolowski
Typo fix.
34
be written with the intention of running remotely on the Smart Scopes Server.</b>
163.98.4 by Marcus Tomlinson
Added "Introduction" and "Local vs remote scopes" sections to tutorial.dox
35
36
(For more information on how to deploy your scope to the Smart Scopes Server, or how to implement a native remote scope using
163.113.28 by Marcus Tomlinson
Fixed warning in documentation.
37
the SSS REST API see: <i>link_not_yet_available</i>)
163.146.1 by Pete Woods
Convert the remote scopes section to a conditional section
38
\endif
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
39
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
40
\section develop Developing scopes
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
41
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
42
\subsection starting Getting started
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
43
163.315.1 by Michi Henning
Lots of doc fixes and updates.
44
A simple C++ scope template with a cmake build system is currently available as part of the Ubuntu SDK IDE. To use it, install the
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
45
packages required for scope development:
163.98.15 by Michal Hruby
Add some basic information on getting the template and deployment, to be completed
46
47
\verbatim
48
sudo apt-get install libunity-scopes-dev
49
\endverbatim
50
163.315.1 by Michi Henning
Lots of doc fixes and updates.
51
Now you are ready to explore and modify the sample code in the src/ directory.
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
52
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
53
\subsection click Click packaging
54
55
To register your scope, you must use the "scope" click hook, and point it to a directory containing your .ini file and .so file.
163.315.1 by Michi Henning
Lots of doc fixes and updates.
56
In the template, a manifest such as the following is used:
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
57
58
\code
59
{
60
  "description": "Net scope description",
163.209.1 by Pete Woods
Incorrect click packaging documentation
61
  "framework": "ubuntu-sdk-14.10-dev1",
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
62
  "hooks": {
63
    "myscope": {
64
      "scope": "myscope", <-- Point to directory in build tree with .ini and .so
65
      "apparmor": "scope-security.json" <-- Point to AppArmor manifest in build tree
66
    }
67
  }
68
  "maintainer": "Some Guy <some.guy@ubuntu.com>",
69
  "name": "com.ubuntu.developer.username.net-scope",
70
  "title": "Some scope",
71
  "version": "0.1"
72
}
73
\endcode
74
163.387.2 by Michi Henning
Fixed a minor doc issue for scopes::Result: protected and private stuff was shown.
75
\subsubsection multiarch_click Multi-arch click packages
163.378.3 by Pete Woods
Docs for multi-arch
76
The search path for the shared library inside a click package is as follows:
77
78
<ul>
79
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/lib${SCOPE_NAME}.so
80
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/${SCOPE_NAME}.so
81
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/scope.so
82
<li>${SCOPE_DIRECTORY}/lib${SCOPE_NAME}.so
83
<li>${SCOPE_DIRECTORY}/${SCOPE_NAME}.so
84
<li>${SCOPE_DIRECTORY}/scope.so
85
</ul>
86
87
Therefore click packges can be made multi-arch aware by compiling your targets for multiple architectures, and creating, e.g. the
88
following directory structure:
89
90
\code
91
├── testscopeA.ini
92
├── testscopeA-settings.ini
93
├── x86_64-linux-gnu
94
|   └── libtestscopeA.so
95
└── arm-linux-gnueabihf
96
    └── libtestscopeA.so
97
\endcode
98
163.378.5 by Pete Woods
Spelling
99
You must also update the manifest file 'architecture' property to enumerate the included architectures, as follows:
163.378.3 by Pete Woods
Docs for multi-arch
100
101
\code
102
    "architecture": ["armhf", "amd64"]
103
\endcode 
104
261.1.12 by Pete Woods
Fix mistakes in multi arch branch
105
\subsubsection multiarch-scoperunner Multi-arch scope runner
163.378.4 by Pete Woods
Multi-arch scoperunner docs
106
Similarly to the shared libraries, when a relative path is provided the search path for custom scope runners is as follows:
107
108
<ul>
109
<li>${SCOPE_DIRECTORY}/${DEB_HOST_MULTIARCH}/${CUSTOM_SCOPERUNNER}
110
<li>${SCOPE_DIRECTORY}/${CUSTOM_SCOPERUNNER}
111
</ul>
112
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
113
\subsubsection apparmor Apparmor manifest
114
163.223.2 by Pete Woods
Remove references to local-content scope
115
Scopes that are packaged using click are inherently untrusted and must be confined. At present, there is only a single type of scope that can be defined:
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
116
<ul>
163.315.1 by Michi Henning
Lots of doc fixes and updates.
117
<li>Network scope - can access the network / internet, but is not allowed to use APIs that provide access to the user's data.
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
118
</ul>
119
163.223.2 by Pete Woods
Remove references to local-content scope
120
The security manifest for this type of scope should be as follows:
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
121
122
\code
123
{
124
    "template": "ubuntu-scope-network",
163.223.1 by Pete Woods
Update the docs and examples to match the new confinement policy
125
    "policy_groups": [],
163.209.1 by Pete Woods
Incorrect click packaging documentation
126
    "policy_version": 1.2
163.154.1 by Pete Woods
Discuss the click packaging in the tutorial documentation
127
}
128
\endcode
129
163.315.1 by Michi Henning
Lots of doc fixes and updates.
130
\subsection impl Implementing a scope
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
131
163.315.1 by Michi Henning
Lots of doc fixes and updates.
132
This short tutorial covers the basic steps and building blocks needed to implement a scope in C++ with unity-scopes-api.
133
For complete examples of various scopes, see the `demo/scopes` subdirectory of the unity-scopes-api source project.
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
134
163.98.2 by Pawel Stolowski
Fixes.
135
A typical scope implementation needs to implement interfaces of the following classes from the Scopes API:
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
136
<ul>
163.315.1 by Michi Henning
Lots of doc fixes and updates.
137
<li>unity::scopes::ScopeBase - the main scope class and entry point for all incoming requests
138
<li>unity::scopes::SearchQueryBase - the handler for search requests
139
<li>unity::scopes::PreviewQueryBase - the handler for preview requests (only if handling previews)
140
<li>unity::scopes::ActivationQueryBase - the handler for activation and preview action requests (only if handling previews and activation)
141
<li>unity::scopes::SearchListenerBase - the handler for search replies (only in aggreagator scopes, to pull results from other scopes)
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
142
</ul>
143
163.315.1 by Michi Henning
Lots of doc fixes and updates.
144
The following sections show explaing these in more detail.
145
146
\subsubsection simplescope Case 1: A simple (non-aggregating) scope
147
148
This is the typical case: a scope that connects to a remote or local backend, such as a database,
149
and provides results in response to search queries coming from a
150
client (that is, the Unity Dash or another scope).
151
152
\paragraph scopebase Implementing ScopeBase
153
154
You must create a class that derives from \link unity::scopes::ScopeBase ScopeBase\endlink and
155
implement a few methods. As a minimum, you must provide implementations of the
156
\link unity::scopes::ScopeBase::search search()\endlink and \link unity::scopes::ScopeBase::preview preview()\endlink methods. 
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
157
158
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
159
using unity::scopes;
160
161
class MyScope : public ScopeBase
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
162
{
163
public:
163.315.1 by Michi Henning
Lots of doc fixes and updates.
164
    virtual void start(std::string const& scope_id) override;  // optional, dflt impl does nothing
165
    virtual void stop() override;                              // optional, dflt impl does nothing
166
    virtual void run() override;                               // optional, dflt impl does nothing
167
    virtual SearchQueryBase::UPtr search(CannedQuery const& query,
168
                                         SearchMetadata const& metadata) override;
169
    virtual PreviewQueryBase::UPtr preview(Result const& result,
170
                                           ActionMetadata const& metadata) override;
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
171
}
172
\endcode
173
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
174
The scopes runtime calls \link unity::scopes::ScopeBase::start() start()\endlink once prior to
163.315.1 by Michi Henning
Lots of doc fixes and updates.
175
sending any queries. You can use it to perform one-time initialization for your scope. Note that you should
176
not perform any lengthy operations in `start()`. Your implementation must return as quickly as possible
177
(in a fraction of the second), so do not, for example, make synchronous network requests as part of `start()`.
178
179
The scope ID passed to `start()` is taken from the name your scope's `.ini` configuration file.
180
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
181
The scopes runtime calls \link unity::scopes::ScopeBase::stop() stop()\endlink to inform your scope
163.315.1 by Michi Henning
Lots of doc fixes and updates.
182
that it should shut down. You can use this method to perform any one-time clean-up.
183
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
184
Prior to sending any queries, the scopes runtime calls \link unity::scopes::ScopeBase::run() run()\endlink if your `start()` method
163.315.1 by Michi Henning
Lots of doc fixes and updates.
185
completed successfully (did not throw an exception). The `run()` method
186
is called by a separate thread that you can use for your own purposes, for example, to run an event loop.
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
187
The scopes runtime has no further interest in this thread, but you must ensure that, if you do not return
163.315.1 by Michi Henning
Lots of doc fixes and updates.
188
from `run()`, you must return from `run()` in response to a call to `stop()`.
189
190
For typical and simple cases, you can ignore `run()`.
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
191
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
192
\paragraph handlingsearch Handling search
163.83.2 by Pawel Stolowski
Described preview and activation handling.
193
327.1.1 by Kyle Fazzari
Fix a couple typos in the tutorial.
194
The unity::scopes::ScopeBase::search() method is called once for each query. Its purpose is to instantiate
163.315.1 by Michi Henning
Lots of doc fixes and updates.
195
and return a new C++ instance that encapsulates the query, that is, `search()` is a factory method.
196
(Do not start execution of the query as part of `search()`; the query object has a separate method for this.)
197
198
`search()` must return an instance of an object that implements the unity::scopes::SearchQueryBase interface, for example:
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
199
200
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
201
202
class MyQuery : public SearchQueryBase { ... };
203
163.83.5 by Pawel Stolowski
More tutorial updates.
204
SearchQueryBase::UPtr MyScope::search(CannedQuery const& query, SearchMetadata const& metadata)
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
205
{
163.213.7 by Pawel Stolowski
Updated tutorial and release notes.
206
    SearchQueryBase::UPtr q(new MyQuery(query, metadata));
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
207
    return q;
208
}
209
\endcode
210
163.315.1 by Michi Henning
Lots of doc fixes and updates.
211
The search() method receives two arguments: a unity::scopes::CannedQuery query object that (among other information) carries the actual
212
query string, and
213
additional parameters for the search request, passed as unity::scopes::SearchMetadata. The metadata includes information such as
214
the current locale string, the form factor, and the query cardinality.
215
216
Cardinality is the maximum number of results expected from a query (a value of 0 indicates no limit). For optimal performance,
217
do not return more results than indicated by the cardinality. If you more than the requested number of results, you are
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
218
wasting resources. (The scopes runtime ignores the additional results.)
163.315.1 by Michi Henning
Lots of doc fixes and updates.
219
163.402.1 by Marcus Tomlinson
Added "Handling aggregation" section
220
\paragraph handlingaggregation Handling aggregation
221
222
As previously stated, SearchMetadata contains additional information about the search requests you receive, including
223
the methods:
224
225
<ul>
226
<li>\link unity::scopes::SearchMetadata::is_aggregated is_aggregated()\endlink - true if the request was initiated by
227
    an aggregator,
228
<li>and \link unity::scopes::SearchMetadata::aggregated_keywords aggregated_keywords()\endlink - the list of keywords
229
    used by the aggregator to find your scope.
230
</ul>
231
232
\note Please refer to the <a href="https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/">Scope Keywords</a>
233
tutorial document for more detail on using keywords in your scope.
234
235
You can use the is_aggregated() method from within
236
\link unity::scopes::SearchQueryBase::run SearchQueryBase::run()\endlink in order to ensure that an appropriate set of
237
results are returned when queried by an aggregator:
238
239
\code{.cpp}
240
void MyQuery::run(SearchReplyProxy const& reply)
241
{
242
    if (metadata_.is_aggregated())
243
    {
244
        auto category = reply->register_category("agg_cat",
245
                                                 "MyScope Featured",
246
                                                 agg_icon);
247
        do_aggregated_search(reply, category);
248
    }
249
    else
250
    {
251
        do_normal_search(reply);
252
    }
253
}
254
\endcode
255
256
You may notice in the code snippet above that for each aggregated search we receive, we register a specific results
257
category. Although aggregators may be willing to accept more than one category from its child scopes, they are only
258
required to accept the first.
259
260
Thereafter, an aggregator may choose to ignore any additional categories the child scope registers. It is therefore
261
recommended that scope authors follow the above method of handling aggregated searches. It is also recommended that
262
your scope provide a decent category title (e.g. "MyScope Featured"). An aggregator is likely to display this category
263
title as is within its result set, so try to keep it clean and descriptive.
264
163.315.1 by Michi Henning
Lots of doc fixes and updates.
265
\paragraph surfacingmode Surfacing mode
266
267
The query string may be the empty string. If so, the UI is asking your scope to produce default results
268
that are shown in what is known as _surfacing mode_. These are the results the UI displays if the user
269
navigates to your scope, but has not entered a query yet. What results to show here depends on how your
270
scope works. For example, for a music scope, the default results could be something like "Most Popular"
271
and "Recently Played"; similarly, for a weather scope, the default results could be for the weather
272
report for the current location. As the scope author, you need to decide what is most appropriate
273
to show in surfacing mode. In the interests of a good user experience, it is important to show _something_
163.350.3 by Michi Henning
Fixed typos in comments and doc.
274
here (if at all possible), so the user gets to see at least some results (instead of being confronted with
163.315.1 by Michi Henning
Lots of doc fixes and updates.
275
a blank screen).
276
163.384.3 by Michi Henning
Added cache read/write. Tests still missing.
277
The runtime automatically saves the results of the most recent surfacing query. If a scope cannot produce
278
a result for a surfacing query (presumably, due to connectivity problems), calling
279
\link unity::scopes::SearchReply::push_surfacing_results_from_cache() push_surfacing_results_from_cache()\endlink
280
pushes the results that were produced by the most recent successful
281
surfacing query from the cache. If your scope cannot produce surfacing results, you can call this
282
method to "replay" the results of the previous surfacing query. In turn, this avoids the user
283
being presented with an empty screen if he/she swipes to the scope while the device does not have connectivity.
284
285
`push_surfacing_results_from_cache()` has an effect only if called for a surfacing query (that is, a query with an empty query string). If called for a non-empty query, it does nothing.
286
287
You must call this method before calling \link unity::scopes::Reply::finished finished()\endlink,
163.384.6 by Michi Henning
Fixed symbols file. Minor doc fix.
288
otherwise no cached results will be pushed. (`push_surfacing_results_from_cache() implicitly calls `finished()`);
163.384.3 by Michi Henning
Added cache read/write. Tests still missing.
289
163.315.1 by Michi Henning
Lots of doc fixes and updates.
290
\paragraph querybase Implementing QueryBase
291
292
You must implement a class that derives from \link unity::scopes::SearchQueryBase SearchQueryBase\endlink and return
293
an instance of this class from `search()`.
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
294
Your class must implement a \link unity::scopes::SearchQueryBase::run run()\endlink method. The scopes runtime calls
163.315.1 by Michi Henning
Lots of doc fixes and updates.
295
`run()` to execute the query.
296
297
The \link unity::scopes::SearchReplyProxy SearchReplyProxy\endlink that is passed to `run()` is an invocation
327.1.1 by Kyle Fazzari
Fix a couple typos in the tutorial.
298
handle that allows you to push results for the query back towards the client. (`SearchReplyProxy` is a `shared_ptr`
163.315.1 by Michi Henning
Lots of doc fixes and updates.
299
to a \link unity::scopes::SearchReply SearchReply\endlink object.)
300
301
Two important methods of `SerchReply` are \link unity::scopes::SearchReply::register_category register_category()\endlink
302
and \link unity::scopes::SearchReply::push push()\endlink.
303
304
`register_category()` is a factory method that registers new categories for the results of this query (see
163.350.1 by Michi Henning
Added Version attribute to Scope.ini and scope metadata.
305
\link unity::scopes::Category\endlink). You can create new categories at any point during query processing. 
306
Categories serve to visually group query results in some way;
307
when you push results for a query, you indicate which
163.315.1 by Michi Henning
Lots of doc fixes and updates.
308
category each particular result belongs to, and the UI renders that result in the corresponding
163.350.1 by Michi Henning
Added Version attribute to Scope.ini and scope metadata.
309
visual group. Categories are rendered in the order in which they are encountered by the UI
310
as you push your results. If you want to control the order in which categories are rendered
311
(for examples, such that a "Breaking News" category always appears first), you may need to
312
buffer the results you receive from your back-end data source until you get a result for that
313
category, and then push that result, plus any other buffered results.
163.315.1 by Michi Henning
Lots of doc fixes and updates.
314
315
Pre-registering categories is the preferred approach because it allows the UI to reserve space
316
and perform layout chores before any query results arrive. (In turn, this permits the UI to
317
optimize its operation.) However, for some data sources, it may not be possible to determine
318
all of the possible categories in advance, in which case you have no choice but to create
319
new categories as they arrive in the data from your scope's data source.
320
321
Do _not_ wait for all results for a query to arrive in an attempt to buffer them and order
322
them by category. If you do, this prevents incremental rendering, and the user sees nothing
323
until your scope has processed _all_ results. To create a positive user experience,
324
your scope should push results as soon as possible.
325
163.443.1 by Michi Henning
Updated doc to clarify that unique category IDs are a bad idea.
326
The UI uses categories to incrementally render the display after a refresh of search results. This relies
327
on categories staying the same from query to query. If your scope has, say, a "News" category, you need
328
to make sure that the category ID and name stay the same from query to query. In particular, do _not_
329
create category IDs that are artificially unique per query (such as by appending a sequence number).
330
163.315.1 by Michi Henning
Lots of doc fixes and updates.
331
When you create a category, you can provide a \link unity::scopes::CategoryRenderer \endlink instance.
332
The category renderer determines the visual appearance of the results in that category (such as
333
display in a grid or in a carousel layout).
334
335
You must wrap each actual search result inside a \link unity::scopes::CategorisedResult CategorisedResult\endlink object and
336
pass the result instance to \link unity::scopes::SearchReply::push push\endlink.
337
338
A typical implementation of `run()` might look like this:
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
339
340
\code{.cpp}
141.1.1 by Michal Hruby
Updated tutorial
341
void MyQuery::run(SearchReplyProxy const& reply)
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
342
{
163.315.1 by Michi Henning
Lots of doc fixes and updates.
343
    if (!valid())
344
    {
345
        return;  // Query was cancelled
346
    }
347
163.16.1 by Michal Hruby
More docs
348
    auto category = reply->register_category("recommended", "Recommended", icon);
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
349
    //... query a local or remote backend
350
163.315.1 by Michi Henning
Lots of doc fixes and updates.
351
    for (auto res : backend.get_results(query().query_string())) // for every result returned by a backend
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
352
    {
353
        ...
141.1.1 by Michal Hruby
Updated tutorial
354
        CategorisedResult result(category); // create a result item in "recommended" category
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
355
        result.set_uri(...);
356
        result.set_title(...);
357
        result.set_art(...);
358
        result.set_dnd_uri(...);
141.1.1 by Michal Hruby
Updated tutorial
359
        result["my-custom-attribute"] = Variant(...); // add arbitrary data as needed
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
360
163.83.2 by Pawel Stolowski
Described preview and activation handling.
361
        if (!reply->push(result)) // send result to the client
362
        {
163.315.1 by Michi Henning
Lots of doc fixes and updates.
363
            break; // false from push() means that the search was cancelled
163.83.2 by Pawel Stolowski
Described preview and activation handling.
364
        }
365
    }
366
}
367
\endcode
368
163.315.1 by Michi Henning
Lots of doc fixes and updates.
369
As far as the UI is concerned, the query is complete when `run()` returns. (While the query can potentially
370
return more results, the UI shows a spinner or similar, to indicate that the query is not complete yet.)
371
372
It is possible for you to return from `run()` _without_ having the query complete automatically. The life time
373
of the query is controlled not only by `run()`, but also by the life time of the `SearchReplyProxy` that is passed
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
374
to `run()`. The scopes runtime monitors the reply proxy and informs the UI that the query is complete when
163.315.1 by Michi Henning
Lots of doc fixes and updates.
375
_either_ `run()` returns _or_ the last reply proxy for the query goes out of scope. This allows you to, for example,
376
pass the reply proxy to a different thread that pushes results (as you might want to do if you need to run a
377
separate event loop). That thread can then also react to query cancellation. The important point is that, if
378
you keep copies of the reply proxy, the query will remain alive until you destroy all copies of the reply proxy
379
for that query (or explicitly call `finished()` on the reply proxy yourself, which explicitly ends the query).
380
381
\paragraph cancellation Query cancellation
382
383
It is possible for the UI to cancel a query before the query has completed and is still running in your scope, potentially
384
producing additional results.
385
Typically, this happens because the user has typed a few characters as the search term (which creates a query for
386
the string up to that point); shortly after this, the user might type another character or two, extending the search string.
387
After a short idle period, the UI cancels the original query and creates a new query for the extended search string.
388
However, the second query will not start until _after_ the previous query has completed.
389
390
\note _Query cancellation happens frequently, and it is important for your scope to react quickly to cancellation!_
391
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
392
The scopes runtime provides several ways for your implementation to react to cancellation:
163.315.1 by Michi Henning
Lots of doc fixes and updates.
393
394
<ul>
395
<li>A `false` return value from `SearchReply::push`. If `push` returns `false`, there is no point in continuing to
396
provide more results.
397
<li>You can poll for cancellation by calling \link unity::scopes::QueryBase::valid QueryBase::valid()\endlink. `valid()`
398
returns `false` once a query is cancelled or has exceeded its cardinality limit.
399
<li>Your query implementation class must override the \link unity::scopes::QueryBase::cancelled QueryBase::cancelled()\endlink
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
400
method. The scopes runtime calls `cancelled()` if the UI has cancelled the query. (Note that calls to `cancelled()` are
163.315.1 by Michi Henning
Lots of doc fixes and updates.
401
made by a separate thread.)
402
</ul>
403
404
Testing the return value from `push()` is reasonable only if you know that results for your scope will
405
arrive quickly (no more than 0.1 seconds apart). Otherwise, you should push results asynchronously from
406
a separate thread and arrange for the query to complete (return from `run()`) in response to the scopes
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
407
runtime calling `cancelled()`.
163.315.1 by Michi Henning
Lots of doc fixes and updates.
408
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
409
Note that it is possible for a call to `cancelled()` to arrive before the scopes runtime has called `run()`
163.315.1 by Michi Henning
Lots of doc fixes and updates.
410
(because `cancelled()` and `run()` are called by different threads and, therefore, can be dispatched out of order).
411
412
163.460.7 by Pawel Stolowski
Added filters section to the tutorial
413
\paragraph filters Filters
414
415
Scopes API offers support for filter widgets, which provide means for filtering search results based on user input other than search query string
416
alone. Filter widgets need to be defined by creating appropriate filters inside the overriden SearchQueryBase::run() method, and then pushed
163.460.9 by Pawel Stolowski
Minor tutorial fixes
417
to the UI. It is recommended to push filters early before search results are pushed for best user experience.
163.460.7 by Pawel Stolowski
Added filters section to the tutorial
418
419
Here is an example of how filters can be created:
420
421
\code{.cpp}
422
void run(SearchReplyProxy const& reply)
423
{
424
    OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("brand", "Brand");
425
    filter1->add_option("audi", "Audi");
426
    filter1->add_option("bmw", "BMW");
427
428
    RangeInputFilter::SPtr filter2 = RangeInputFilter::create("price", Variant(0.0f), Variant::null(), "Min", "", "", "Max", "");
429
    ValueSliderFilter::SPtr filter3 = ValueSliderFilter::create("horsepower", 1, 135, 50, ValueSliderLabels("Min", "Max"));
430
431
    Filters filters;
432
    filters.push_back(filter1);
433
    filters.push_back(filter2);
434
    filters.push_back(filter3);
435
436
    reply->push(filters, query().filter_state());
437
438
    // push search results here
439
\endcode
440
441
Scopes are free to change filters at any time - with every execution of search the scope can omit any of the previously visible filters or add new ones, if that
442
makes sense for particular use cases.
443
444
Filters act only as UI widgets - it is the responsibility of the scope to check their state and actually apply them to search results. The current value of a filter
445
becomes just another parameter of the search query that needs to be taken into account in the implementation of search handling inside run().
446
447
To examine current state of the filters, pass the instance of unity::scopes::FilterState received with search query to respective methods of
448
the filters. For example:
449
450
\code{.cpp}
451
void run(SearchReplyProxy const& reply)
452
{
453
    // filter creation code omitted here
454
    auto state = query().filter_state();
455
    int search_start = 0;
456
    int search_end = 1000;
457
    if (rangefilter->has_start_value(state)) {
458
        search_start = rangefilter->start_value(state);
459
    }
460
    if (rangefilter->has_end_value(state)) {
461
        search_end = rangefilter->end_value(state);
462
    }
463
464
    // apply search_start and search_end to search logic
465
\endcode
466
467
The scope may nominate a single filter to act as "primary navigation". This is only possible if departments are not used at the same time (in which case departments
163.460.9 by Pawel Stolowski
Minor tutorial fixes
468
become a primary navigation tool). An attempt to nominate a filter to be a "primary navigation" while departments are present is ignored by the UI and the
469
filter acts as a regular filter. Also, only a single-selection OptionSelectorFilter can currently be promoted to be primary navigation. To do this, set the display
163.460.7 by Pawel Stolowski
Added filters section to the tutorial
470
hints to FilterBase::DisplayHints::Primary:
471
472
\code{.cpp}
473
OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("brand", "Brand");
474
filter1->set_display_hints(FilterBase::DisplayHints::Primary);
475
filter1->add_option("audi", "Audi");
476
\endcode
477
478
When a filter becomes a primary navigation filter, it gets displayed in the search box drop-down, below recent searches, so it's readily available for quick access.
479
Also, currently selected option is displayed as a "brick" in the search box, hinting the user about the context of current search. All the other filters can be
480
revealed via the filters panel icon.
481
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
482
\paragraph handlingpreview Handling previews
163.83.2 by Pawel Stolowski
Described preview and activation handling.
483
163.315.1 by Michi Henning
Lots of doc fixes and updates.
484
Your scope is responsible for handling preview requests for results it has returned; you implement this by overriding
485
the unity::scopes::ScopeBase::preview() method:
163.83.2 by Pawel Stolowski
Described preview and activation handling.
486
487
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
488
class MyScope : public unity::scopes::ScopeBase
163.83.2 by Pawel Stolowski
Described preview and activation handling.
489
{
490
public:
491
    ...
163.315.1 by Michi Henning
Lots of doc fixes and updates.
492
    virtual PreviewQueryBase::UPtr preview(Result const& result, ActionMetadata const& metadata) override;
163.83.2 by Pawel Stolowski
Described preview and activation handling.
493
    ...
494
}
495
\endcode
496
163.315.1 by Michi Henning
Lots of doc fixes and updates.
497
This method must return an instance derived from unity::scopes::PreviewQueryBase. Like `search()`, `preview()` is a factory method;
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
498
the scopes runtime initiates the actual preview by calling \link unity::scopes::PreviewQueryBase::run run()\endlink on the instance you
163.315.1 by Michi Henning
Lots of doc fixes and updates.
499
return. Your `run()` method is responsible for gathering preview data (from
500
local or remote sources) and passing it to the UI along with the definition of the visual appearance of the preview by calling
501
\link unity::scopes::PreviewReply::push push()\endlink on the reply proxy that is passed to `run()`. (This is analogous to returning
502
results from `search()`.)
503
504
A preview consists of one or more preview widgets. Preview widgets are the basic building blocks for previews, such as a header with a title and subtitle, an image, a
505
gallery with multiple images, a list of audio tracks, and so on.(See unity::scopes::PreviewWidget for a list of supported widget types.)
506
Your implementation of \link unity::scopes::PreviewQueryBase::run run()\endlink must create and populate one or more preview widgets
507
and push them to the UI.
508
509
Each preview widget has a unique identifier, a type name, and a set of attributes determined by the widget's type.
510
For example, a widget of "image" type expects two attributes: "source" (a URI that should point at an image),
511
and a "zoomable" flag that determines if the image should be zoomable.
512
You can specify the values of these attributes explicitly, or you can arrange for the values to be taken from a result
513
that the corresponding query returned earlier, by referencing the corresponding \link unity::scopes::Result Result\endlink instance.
514
You can also push the value for a referenced attribute separately as part of your implementation of `run()`.
515
516
You provide attributes explicitly by calling
517
\link unity::scopes::PreviewWidget::add_attribute_value PreviewWidget::add_attribute_value()\endlink:
518
519
\code{.cpp}
520
PreviewWidget image_widget("myimage", "image");
521
522
image_widget.add_attribute_value("source", Variant("file:///tmp/image.jpg"));
523
image_widget.add_attribute_value("zoomable", Variant(false));
524
\endcode
525
526
To reference values from results or arbitrary values that you push separately, use
527
\link unity::scopes::PreviewWidget::add_attribute_mapping PreviewWidget::add_attribute_mapping()\endlink:
528
529
\code{.cpp}
530
PreviewWidget image_widget("myimage", "image");
531
image_widget.add_attribute_mapping("source", "art"); // use 'art' attribute from the result
532
image_widget.add_attribute_mapping("zoomable", "myzoomable"); // 'myzoomable' not specified, but pushed below
533
reply->push("myzoomable", Variant(true));
534
\endcode
535
536
To push preview widgets to the client, use \link unity::scopes::PreviewReply::push PreviewReply::push()\endlink:
537
538
\code{.cpp}
539
PreviewWidget image_widget("myimage", "image");
540
PreviewWidget header_widget("myheader", "header");
541
// fill in widget attributes
542
...
543
PreviewWidgetList widgets { image_widget, header_widget };
544
reply->push(widgets);
163.83.2 by Pawel Stolowski
Described preview and activation handling.
545
\endcode
546
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
547
\paragraph previewactions Preview actions
163.83.2 by Pawel Stolowski
Described preview and activation handling.
548
163.315.1 by Michi Henning
Lots of doc fixes and updates.
549
Previews can have actions, such as buttons that the user can press. Actions are supported by a preview widget of type "actions".
550
An actions widget holds one or more action button definitions, where each definition has a unique identifier, a label,
551
and an optional icon. For example, a widget with two buttons, "Open" and "Download", can be defined as follows
552
(using the \link unity::scopes::VariantBuilder VariantBuilder\endlink helper class):
163.83.2 by Pawel Stolowski
Described preview and activation handling.
553
554
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
555
556
PreviewWidget buttons("mybuttons", "actions");
557
558
VariantBuilder builder;
559
builder.add_tuple({
560
    {"id", Variant("open")},
561
    {"label", Variant("Open")}
562
});
563
builder.add_tuple({
564
    {"id", Variant("download")},
565
    {"label", Variant("Download")}
566
});
567
568
buttons.add_attribute_value("actions", builder.end());
163.83.2 by Pawel Stolowski
Described preview and activation handling.
569
\endcode
570
163.315.1 by Michi Henning
Lots of doc fixes and updates.
571
To respond to activation of preview actions, your scope must implement
572
\link unity::scopes::ScopeBase::perform_action ScopeBase::perform_action\endlink:
163.83.2 by Pawel Stolowski
Described preview and activation handling.
573
574
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
575
class MyScope : public ScopeBase
163.83.2 by Pawel Stolowski
Described preview and activation handling.
576
{
163.315.1 by Michi Henning
Lots of doc fixes and updates.
577
    ...
578
    virtual ActivationQueryBase::UPtr perform_action(Result const& result,
579
                                                     ActionMetadata const& metadata,
580
                                                     std::string const& widget_id,
581
                                                     std::string const& action_id) override
163.83.2 by Pawel Stolowski
Described preview and activation handling.
582
    ...
583
}
584
\endcode
585
163.315.1 by Michi Henning
Lots of doc fixes and updates.
586
Like `search()` and `preview()`, `perform_action()` is a factory method. It must return an
587
instance that derives from \link unity::scopes::ActivationQueryBase ActivationQueryBase\endlink.
588
Your derived class must implement the \link unity::scopes::ActivationQueryBase::activate activate()\endlink method,
589
whose job it is to respond to the activation (that is, the user pressing a button). `activate` must return
590
an \link unity::scopes::ActivationResponse ActivationResponse\endlink, which tells the UI how it should
591
behave in response to the activation. For example, your `activate()` could direct the UI to
592
run a new search as follows:
163.83.2 by Pawel Stolowski
Described preview and activation handling.
593
594
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
595
class MyActivation : public ActivationQueryBase
163.83.2 by Pawel Stolowski
Described preview and activation handling.
596
{
163.315.1 by Michi Henning
Lots of doc fixes and updates.
597
    MyActivation(Result const& result, unity::scopes::ActionMetadata const& metadata) :
163.213.7 by Pawel Stolowski
Updated tutorial and release notes.
598
        ActivationQueryBase(result, metadata)
599
    {
600
    }
601
163.315.1 by Michi Henning
Lots of doc fixes and updates.
602
    virtual ActivationResponse activate() override
163.83.2 by Pawel Stolowski
Described preview and activation handling.
603
    {
604
        ...
163.213.7 by Pawel Stolowski
Updated tutorial and release notes.
605
        if (action_id() == "search-grooveshark")
163.83.2 by Pawel Stolowski
Described preview and activation handling.
606
        {
163.98.8 by Michal Hruby
A few fixes to reflect latest API
607
            CannedQuery query("com.canonical.scopes.grooveshark");
163.83.2 by Pawel Stolowski
Described preview and activation handling.
608
            query.set_query_string("metal");
163.315.1 by Michi Henning
Lots of doc fixes and updates.
609
            return ActivationResponse(query);
163.83.2 by Pawel Stolowski
Described preview and activation handling.
610
        }
611
        ...
612
    }
163.315.1 by Michi Henning
Lots of doc fixes and updates.
613
};
163.83.2 by Pawel Stolowski
Described preview and activation handling.
614
\endcode
615
163.98.10 by Pawel Stolowski
Changed structure, make it appear on main page.
616
\paragraph handlingactivation Handling result activation
163.83.2 by Pawel Stolowski
Described preview and activation handling.
617
163.315.1 by Michi Henning
Lots of doc fixes and updates.
618
In many cases, the user can activate search results directly, by tapping on them, provided the result's schema (such as "http://")
619
has a handler in the system. If this is the case, you need not do anything for activation. However, if your scope uses
620
schemas without a handler, the shell will ignore the activation. (Nothing happens in response to a tap by the user.)
163.108.1 by Pawel Stolowski
Some more clarification on result activation handling doc.
621
163.315.1 by Michi Henning
Lots of doc fixes and updates.
622
If you want to intercept such activations (either for schemas without a handler, or to generally intercept result activation),
623
you must implement the \link unity::scopes::ScopeBase::activate ScopeBase::activate()\endlink method:
163.83.2 by Pawel Stolowski
Described preview and activation handling.
624
625
\code{.cpp}
626
class MyScope : public ScopeBase
627
{
163.315.1 by Michi Henning
Lots of doc fixes and updates.
628
    virtual ActivationQueryBase::UPtr activate(Result const& result,
629
                                               ActionMetadata const& metadata) override;
163.83.2 by Pawel Stolowski
Described preview and activation handling.
630
    ...
631
}
632
\endcode
633
163.315.1 by Michi Henning
Lots of doc fixes and updates.
634
In addition, you must call \link unity::scopes::Result::set_intercept_activation Result::set_intercept_activation()\endlink
635
for all results that should trigger a
636
call to your `activate()` method. Your implementation of `activate()` should follow the same guidelines as for
637
`perform_action()` (except that widget and action identifiers do not apply to result activation).
638
163.474.1 by Pawel Stolowski
Added section about in-card action activation
639
\paragraph resultaction Handling result action activation
640
163.474.6 by Pawel Stolowski
Minor grammar fixes
641
Search results can embed simple action buttons (icons) in their cards. When the user taps an action icon, the scope gets notified and can update
642
the affected result card to reflect the new state. A typical use case for this is to offer "social" actions, such as thumbs up/down buttons.
163.474.1 by Pawel Stolowski
Added section about in-card action activation
643
644
The following snippet demonstrates how two actions can be added to a \link unity::scopes::CategorisedResult CategorisedResult\endlink:
645
646
\code
647
CategorisedResult res(cat);
648
res.set_uri("myuri");
649
res.set_title("My Title");
650
651
// Add result actions
652
VariantBuilder builder;
653
builder.add_tuple({
654
        {"id", Variant("thumbsup")},
655
        {"icon", Variant("thOff")},
656
        {"temporaryIcon", Variant("thOn")},
657
        {"label", Variant("I like it")},
658
});
659
builder.add_tuple({
660
        {"id", Variant("flag")},
661
        {"icon", Variant("flag")},
662
        {"temporaryIcon", Variant("flagOn")},
663
        {"label", Variant("Flag this result")},
664
});
163.474.3 by Pawel Stolowski
Renamed social_attributes to social-actions
665
res["social-actions"] = builder.end();
163.474.1 by Pawel Stolowski
Added section about in-card action activation
666
\endcode
667
668
The attributes of result actions are as follows:
669
<ul>
670
<li>id - unique action identifier that will be reported to the scope.
163.474.6 by Pawel Stolowski
Minor grammar fixes
671
<li>icon - the icon for the action button.
672
<li>temporaryIcon (optional) - defines an icon that will be shown immediately when the user taps the button, before the scope reacts to the action.
673
<li>label - the text shown next to the icon.
163.474.1 by Pawel Stolowski
Added section about in-card action activation
674
</ul>
675
676
To respond to activation of result actions, your scope must implement
677
\link unity::scopes::ScopeBase::activate_result_action ScopeBase::activate_result_action\endlink:
678
679
\code{.cpp}
680
class MyScope : public ScopeBase
681
{
682
    ...
683
    ActivationQueryBase::UPtr activate_result_action(Result const& result,
684
            ActionMetadata const& metadata,
685
            std::string const& action_id) override;
686
    ...
687
}
688
\endcode
689
690
Like `search()` and `preview()`, `activate_result_action()` is a factory method. It must return an
691
instance that derives from \link unity::scopes::ActivationQueryBase ActivationQueryBase\endlink.
692
Your derived class must implement the \link unity::scopes::ActivationQueryBase::activate activate()\endlink method,
693
whose job it is to respond to the activation (that is, the user pressing action button). `activate` must return
694
an \link unity::scopes::ActivationResponse ActivationResponse\endlink, which tells the UI how it should
695
behave in response to the result action activation. For result actions the typical and recommended behavior is to update the card
696
for the result whose action was activated.
697
163.474.6 by Pawel Stolowski
Minor grammar fixes
698
For example, here is how to update the actions of an affected card in response to a "thumbsup" action, so that tapping the "thumbsup" action button replaces that
163.474.1 by Pawel Stolowski
Added section about in-card action activation
699
button with "thumbsdown":
700
701
\code{.cpp}
702
class MyActivation : public ActivationQueryBase
703
{
704
    MyActivation(Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& action_id) :
705
        ActivationQueryBase(result, metadata, action_id)
706
    {
707
    }
708
709
    virtual ActivationResponse activate() override
710
    {
711
        if (action_id() == "thumbsup")
712
        {
713
            // ... update backend data for 'thumbs up' action ...
714
715
            // get the affect result and update it
716
            Result updatedRes(result());
717
            VariantBuilder builder;
718
            builder.add_tuple({
719
                    {"id", Variant("thumbsdown")},
720
                    {"icon", Variant("thOn")},
721
                    {"temporaryIcon", Variant("thOff")},
722
                    {"label", Variant("I don't like it")},
723
            });
724
            builder.add_tuple({ ... })
163.474.4 by Pawel Stolowski
Fix typo
725
            updatedRes["social-actions"] = builder.end();
163.474.1 by Pawel Stolowski
Added section about in-card action activation
726
            return ActivationResponse(updatedRes);
727
        }
728
729
        if (action_id() == "thumbsdown")
730
        ...
731
    }
732
};
733
\endcode
734
163.315.1 by Michi Henning
Lots of doc fixes and updates.
735
\paragraph export Exporting a scope
736
737
Your scope must be compiled into a `.so` shared library and, to be successfully
738
loaded at runtime, it must provide two C functions to create and destroy it.
739
A typical code snippet to do this looks as follows:
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
740
741
\code{.cpp}
163.315.1 by Michi Henning
Lots of doc fixes and updates.
742
extern "C"
743
{
744
    unity::scopes::ScopeBase* UNITY_SCOPE_CREATE_FUNCTION()
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
745
    {
746
        return new MyScope();
747
    }
748
163.315.1 by Michi Henning
Lots of doc fixes and updates.
749
    void UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base)
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
750
    {
751
        delete scope_base;
752
    }
753
}
754
\endcode
755
163.464.4 by Pawel Stolowski
Doc fixes
756
\paragraph inlineplayback Inline music playback
757
758
Results which represent music (songs, albums etc.) can contain an extra data about audio content and can then be played directly from the Dash.
759
Such results have a "play" button overlaid on them. To create results that support this functionality two conditions must be met:
760
<ul>
761
<li>Category renderer definition must contain the "quick-preview-type" key with the value of "audio" in the "template" section;
762
<li>Results in the respective category must contain a "quick-preview-data" attribute, each of them is a dictionary with the extra playback data described
763
below.
764
</ul>
765
766
The data assigned to "quick-preview-data" attribute of a Result needs to contain the following keys:
767
<ul>
768
<li>uri - a playable uri of a media file (path of a local file, or http uri).
769
<li>duration - the duration of the media file, in seconds.
163.464.5 by Pawel Stolowski
-the
770
<li>playlist - an array of uris of additional songs, e.g. songs from same album; they will be played in sequence when the main
163.464.4 by Pawel Stolowski
Doc fixes
771
song denoted by 'uri' finishes.
772
</ul>
773
774
Here is an example of a category renderer for inline playback, which uses component mapping to map quick-preview-data to audio-data attribute of a result:
775
\code{.cpp}
776
static const char CATEGORY_RENDERER[] = R"(
777
{
778
  "schema-version": 1,
779
  "template": {
780
    "category-layout": "grid",
781
    "card-size": "large",
782
    "card-layout" : "horizontal",
783
    "quick-preview-type" : "audio"
784
  },
785
  "components": {
786
    "title": "title",
787
    "art": {
788
      "field": "art"
789
    },
790
    "subtitle": "artist",
791
    "quick-preview-data": {
792
        "field": "audio-data"
793
    }
794
  }
795
}
796
)";
797
\endcode
798
799
A sample code that creates a result card representing a song and all songs from same album in a background playlist may look this way:
800
\code{.cpp}
801
802
CategorisedResult res(category);
803
res.set_uri(uri);
804
res.set_title(media.getTitle());
805
...
806
807
VariantMap inline_playback_data;
808
inline_playback_data["uri"] = uri;
809
inline_playback_data["duration"] = song_duration_in_seconds;
810
VariantArray playlist;
811
for (const std::string& song: album_songs)
812
{
813
    playlist.push_back(Variant(song.getUri()));
814
}
815
inline_playback_data["playlist"] = playlist;
816
res["audio-data"] = inline_playback_data;
817
818
\endcode
819
163.315.1 by Michi Henning
Lots of doc fixes and updates.
820
\subsubsection aggscope Case 2: An aggregating scope
821
822
Aggregating scopes are scopes that collect results from other scopes and possibly consolidate, modify, or re-categorise
823
the results in some way. In other words, for an aggregating scope, the data source(s) are other scopes rather than,
824
say, a remote web service.
825
826
To receive results from its child scopes, your scope must implement a class that derives from
827
\link unity::scopes::SearchListenerBase SearchListenerBase\endlink. You provide an instance
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
828
of this class to each sub-query; the scopes runtime invokes callback methods on this class
163.315.1 by Michi Henning
Lots of doc fixes and updates.
829
to let you know when a new result or status update arrives, and when a query completes.
830
163.402.2 by Marcus Tomlinson
Updated "Finding child scopes" section to include the use of find_child_scopes() in aggregators
831
\paragraph childscopes Finding child scopes
163.315.1 by Michi Henning
Lots of doc fixes and updates.
832
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
833
To send queries to its child scopes, your scope must obtain a proxy for each child scope. The scopes runtime
163.315.1 by Michi Henning
Lots of doc fixes and updates.
834
runs a registry process. The job of the registry (among other things) is to provide information about available
835
scopes (whether they are local scopes or remote scopes in the Smartscopes server).
836
837
You can obtain the proxy for a child scope by calling  \link unity::scopes::Registry::get_metadata get_metadata()\endlink
838
on the registry, supplying the ID of the child scope. The return value is an instance of type
839
\link unity::scopes::ScopeMetadata ScopeMetadata\endlink that describes the scope and also provides access to the
840
proxy for the scope.
841
163.402.2 by Marcus Tomlinson
Updated "Finding child scopes" section to include the use of find_child_scopes() in aggregators
842
You can also aggregate scopes indirectly via keyword(s). Keywords describe the type of content a scope provides (e.g.
843
a scope with the keyword "music" will return music results, the "video" keyword indicates video content, and so on).
844
You can obtain child scopes via keywords by calling \link unity::scopes::Registry::list_if list_if()\endlink on the
845
registry, supplying a predicate function. The return value is a map containing only those scopes for which the predicate
846
returns true. Therefore, your predicate function should return true for all scopes matching the keyword(s) you wish to
847
aggregate.
848
849
\note Please refer to the <a href="https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/">Scope Keywords</a>
850
tutorial document for a list of recommended keywords to use.
851
852
As an aggregator scope author you must provide an implementation of the virtual
853
\link unity::scopes::ScopeBase::find_child_scopes ScopeBase::find_child_scopes()\endlink method. All logic for finding
854
your aggregator's child scopes should be implemented within this method. The return value is of type
855
\link unity::scopes::ChildScopeList ChildScopeList\endlink and must contain an instance of
856
\link unity::scopes::ChildScope ChildScope\endlink for each scope your aggregator may collect results from.
857
858
Here is how you could implement find_child_scopes() to return all scopes in the registry that contain the keywords
859
"sports" and "news":
860
861
\code{.cpp}
862
ChildScopeList MyScope::find_child_scopes() const override
863
{
864
    auto sportsnews_scopes = registry()->list_if([](ScopeMetadata const& item)
865
    {
866
        auto keywords = item.keywords();
867
        return (keywords.find("sports") != keywords.end()) &&
868
               (keywords.find("news") != keywords.end());
869
    });
870
871
    ChildScopeList list;
872
    for (auto const& sportsnews_scope : sportsnews_scopes)
873
    {
874
        list.emplace_back(ChildScope{sportsnews_scope.first,  // Child scope ID
875
                                     sportsnews_scope.second, // Child scope metadata
876
                                     true,                    // Default enabled state (when first discovered)
877
                                     {"sports", "news"}});    // Keywords used to aggregate this scope
878
    }
879
    return list;
880
}
881
\endcode
882
163.315.1 by Michi Henning
Lots of doc fixes and updates.
883
\paragraph subquery Sub-queries
884
163.366.9 by Pawel Stolowski
Updated tutorial.
885
To send a query to another scope, use one of the `subsearch()` overloads of \link unity::scopes::SearchQueryBase\endlink
163.315.1 by Michi Henning
Lots of doc fixes and updates.
886
inside your implementation of
887
\link unity::scopes::SearchQueryBase::run SearchQueryBase::run()\endlink.
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
888
This method requires a handle to the child scope to query (either via proxy or ChildScope handle), the query details
889
(\link unity::scopes::CannedQuery CannedQuery\endlink), plus an instance of your `SearchListenerBase` implementation
890
that will receive the query results.
163.315.1 by Michi Henning
Lots of doc fixes and updates.
891
892
\note `subsearch()` is identical to
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
893
\link unity::scopes::ScopeBase::search search()\endlink but, for `subsearch()`, the scopes runtime transparently
163.315.1 by Michi Henning
Lots of doc fixes and updates.
894
forwards query cancellation to child scopes, so your implementation of \link unity::scopes::QueryBase::cancelled QueryBase::cancelled()\endlink
895
does not need to forward cancellation to its children.
896
(However, your query class still needs to react to cancellation and should terminate the current query
897
is quickly as possible in response to a cancelled message.)
898
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
899
You should always call \link unity::scopes::ScopeBase::child_scopes ScopeBase::child_scopes()\endlink from within your
900
aggregator's \link unity::scopes::ScopeBase::search search()\endlink method in order to retrieve the latest child
901
scopes list containing the most recent "enabled" states. You can then pass this list into your instantiation of
902
SearchQueryBase for later use.
903
904
\note An aggregator must respect the "enabled" states of its child scopes, querying only the child scopes that are
905
enabled.
906
163.315.1 by Michi Henning
Lots of doc fixes and updates.
907
Here is how you could implement an aggregating scope that passes a query to a single child scope "scope-A":
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
908
909
\code{.cpp}
910
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
911
ChildScopeList MyScope::find_child_scopes() const override
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
912
{
163.315.1 by Michi Henning
Lots of doc fixes and updates.
913
    auto reg = registry();  // Up-call into base class
914
    if (!reg)
915
    {
916
        throw ConfigException(scope_id + ": No registry available, cannot locate child scopes");
917
    }
918
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
919
    ChildScopeList list;
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
920
    try
921
    {
163.315.1 by Michi Henning
Lots of doc fixes and updates.
922
        auto meta = reg->get_metadata("scope-A");
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
923
        list.emplace_back(ChildScope{"scope-A",  meta});
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
924
    }
925
    catch (NotFoundException const& e)
926
    {
927
        ...
928
    }
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
929
    return list;
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
930
}
931
163.315.1 by Michi Henning
Lots of doc fixes and updates.
932
QueryBase::UPtr MyScope::search(CannedQuery const& query,
933
                                SearchMetadata const& metadata)
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
934
{
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
935
    SearchQueryBase::UPtr q(new MyQuery(query, metadata, child_scopes()));
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
936
    return q;
937
}
938
939
...
940
163.315.1 by Michi Henning
Lots of doc fixes and updates.
941
void MyQuery::run(SearchReplyProxy const& upstream_reply) 
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
942
{
163.402.3 by Marcus Tomlinson
Updated "Sub-queries" section to use find_child_scopes() and child_scopes() methods
943
    // Continue only if our child scope is installed AND enabled
944
    if (!child_scopes_.empty() && child_scopes_.front().enabled)
945
    {
946
        auto category = reply->register_category("recommended", "Recommended", icon, "");
947
        SearchListenerBase::SPtr reply(new MyReceiver(upstream_reply, category));
948
        subsearch(child_scopes_.front(), query_, reply);
949
    }
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
950
}
951
\endcode
952
163.315.1 by Michi Henning
Lots of doc fixes and updates.
953
Note that the `subsearch()` call is asynchronous and returns immediately. Despite this, your `MyQuery` instance is kept alive
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
954
because the scopes runtime does not delete it until the child query has completed. (The runtime tracks the `reply` proxy
163.315.1 by Michi Henning
Lots of doc fixes and updates.
955
for the query and holds the query alive until it receives a finished message from the child scope.)
956
957
\paragraph receiver Receiving sub-query results
958
959
Here is a simple implementation of a receiver that passes all child categories and results through to
960
its parent without change. Of course, a more realistic aggregating scope will typically aggregate from
961
more than one child and probably de-duplicate, collate, or otherwise modify child results before passing
962
them upstream.
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
963
964
\code{.cpp}
965
163.315.1 by Michi Henning
Lots of doc fixes and updates.
966
class MyReceiver: public SearchListenerBase
967
{
968
public:
969
    virtual void push(Category::SCPtr const& category) override
970
    {
971
        upstream_reply_->register_category(category);
972
    }
973
974
    virtual void push(CategorisedResult result) override
975
    {
976
        upstream_reply_->push(std::move(result));
977
    }
978
979
    MyReceiver(SearchReplyProxy const& upstream_reply) :
980
        upstream_reply_(upstream_reply)
981
    {
982
    }
983
984
private:
985
    SearchReplyProxy upstream_reply_;
986
};
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
987
\endcode
988
163.366.12 by Michi Henning
Reworked documentation.
989
\paragraph aggbuffering Controlling category order
990
991
Categories are displayed in the order their results are pushed. This can pose a challenge
992
for aggregator scopes because results from child scopes often arrive
993
in random order. To control the order in which categories are rendered,
994
the aggregator must buffer and potentially re-order results by
995
category before pushing them.
996
997
\link unity::scopes::utility::BufferedResultForwarder BufferedResultForwarder\endlink makes
998
it easier to do this.
999
To use the class, you create one instance for each child scope and chain the instances together
1000
in the desired order of categories. Each forwarder buffers results until its predecessor in
1001
the chain indicates that it has completed its category ordering, at which point it itself pushes
1002
any results it has buffered so far and indicates to its follower that it is ready.
1003
1004
By default, a forwarder indicates that it it is ready (has completed ordering) as soon as it has received
1005
a single result. This is useful if an aggregator has child scopes that produce results
1006
for a single category each. In this case, the order of the forwarders determines which
1007
category (the one used by child A or by child B) appears first when the results are rendered.
1008
1009
If an aggregator collates results from children that each produce results for more than
1010
one category, you can override the default implementation of
1011
\link unity::scopes::utility::BufferedResultForwarder::push push()\endlink to change
1012
categories for results from its child, and/or indicate
1013
that it is ready only once the child has provided results for all expected categories.
1014
(See \link unity::scopes::utility::BufferedResultForwarder BufferedResultForwarder\endlink
1015
for more details.)
163.366.9 by Pawel Stolowski
Updated tutorial.
1016
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1017
\paragraph aggactiv Activation and preview
1018
1019
If an aggregator scope simply forwards the results it receives from other scopes (possibly changing their category),
1020
the aggregator need not do anything special for previews, preview actions, or result activation. In this case,
1021
previews, preview actions, and result activation are sent to the scope that produced the corresponding result.
1022
1023
If, however, an aggregator scope changes attributes of results (or creates completely new results that "replace"
1024
received results), you must take extra care:
163.83.5 by Pawel Stolowski
More tutorial updates.
1025
<ul>
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1026
<li>If the original original scope should still handle preview (and activation) requests for a modified result, you must store
1027
a copy of the original result in the modified (or new) result by calling \link unity::scopes::Result::store Result::store()\endlink.
1028
Preview requests for such a result will automatically trigger the scope that created the innermost stored result.
1029
1030
\note Making changes to a receive result but failing to store the original result with the change can cause
1031
in unexpected behavior: a scope could receive a modified result and, depending the exact changes, may
1032
not be able to correctly deal with the result.
1033
1034
<li>If an aggregator creates a completely new result that replaces the original result but does not also store a copy of
1035
the original result, the aggregator _must_ handle preview and activation requests (if the intercept flag is set).
1036
The actions to take are the same as for a non-aggregating scope (see \ref handlingpreview and \ref handlingactivation).
163.83.5 by Pawel Stolowski
More tutorial updates.
1037
</ul>
1038
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1039
Here is an example `push()` implementation that modifies a result and stores a copy, so the original scope
1040
can handle preview and activation:
163.83.5 by Pawel Stolowski
More tutorial updates.
1041
1042
\code{.cpp}
1043
void MyReceiver::push(CategorisedResult original_result)
1044
{
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1045
    // agg_category is a category that aggregates all results from other scopes
1046
    CategorisedResult result(agg_category);
163.83.5 by Pawel Stolowski
More tutorial updates.
1047
    result.set_uri(original_result.uri());
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1048
    result.set_title(original_result.title() + " (aggregated)");
163.83.5 by Pawel Stolowski
More tutorial updates.
1049
    result.set_art(original_result.art());
1050
    result.store(original_result);
1051
1052
    upstream_->push(std::move(result));
1053
}
1054
\endcode
163.83.3 by Pawel Stolowski
Fist cut at agg activation / preview doc.
1055
163.437.1 by Michi Henning
Added doc about how method calls are partitioned onto threads.
1056
\subsection threading Threading model
1057
1058
It is important to understand how the runtime uses threads to call methods on scopes and clients.
1059
The runtime maintains a number of threads that each call one or more methods. Methods in the same
1060
group are always called by the same thread. This means that methods in the same group do not run concurrently,
1061
but methods in different groups _do_ run concurrently. If you share state between methods in
1062
different groups, you _must_ synchronize access to that state, otherwise your code will suffer from
1063
race conditions.
1064
1065
The following lists shows how methods are grouped. Each group has a single dedicated dispatch thread.
1066
1067
<ul>
163.437.2 by Michi Henning
Added initialization methods to thread discussion. Minor rewording for clarity.
1068
<li>\link UNITY_SCOPE_CREATE_FUNCTION()\endlink,
1069
\link unity::scopes::ScopeBase::start() ScopeBase::start()\endlink,
1070
\link unity::scopes::ScopeBase::stop() ScopeBase::stop()\endlink, and
163.437.5 by Michi Henning
Added missing parens to symbol in tutorial.
1071
\link UNITY_SCOPE_DESTROY_FUNCTION()\endlink.
163.437.1 by Michi Henning
Added doc about how method calls are partitioned onto threads.
1072
<li>\link unity::scopes::ScopeBase::search() ScopeBase::search()\endlink,
1073
\link unity::scopes::ScopeBase::preview() ScopeBase::preview()\endlink, and
1074
\link unity::scopes::ScopeBase::perform_action() ScopeBase::perform_action()\endlink.
1075
<li>\link unity::scopes::SearchQueryBase::run() SearchQueryBase::run()\endlink,
1076
\link unity::scopes::PreviewQueryBase::run() PreviewQueryBase::run()\endlink, and
1077
\link unity::scopes::ActivationQueryBase::activate() ActivationQueryBase::activate()\endlink.
1078
<li>\link unity::scopes::QueryBase::cancelled() QueryBase::cancelled()\endlink.
1079
<li>\link unity::scopes::SearchListenerBase::push() SearchListenerBase::push()\endlink,
1080
\link unity::scopes::PreviewListenerBase::push() PreviewListenerBase::push()\endlink,
1081
\link unity::scopes::ActivationListenerBase::activated() ActivationListenerBase::activated()\endlink,
1082
\link unity::scopes::ListenerBase::finished() ListenerBase::finished()\endlink,
1083
\link unity::scopes::ListenerBase::info() ListenerBase::info()\endlink.
1084
</ul>
1085
For your scope implementation, keep in mind that `cancelled()` is _not_ called by
1086
the same thread that called, for example, `search()` or `run()`. This means that any state you
1087
established in `search()` or `run()` must be synchronized if you use that state in `cancelled()`.
1088
1089
Similar considerations apply for aggregating scopes, which act as both client and server: you must
163.437.2 by Michi Henning
Added initialization methods to thread discussion. Minor rewording for clarity.
1090
synchronize any state that is shared between the client side and the server side. For example,
1091
you must synchronize state established in `search()` and accessed from `push()` or `finished()`.
163.437.1 by Michi Henning
Added doc about how method calls are partitioned onto threads.
1092
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1093
\subsection scopesettings Settings
1094
1095
A scope can provide for simple customizations, such as allowing the user to configure an email address or
1096
select a distance unit as metric or imperial.
1097
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1098
\subsubsection settings_definitions Defining settings
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1099
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1100
You can define such settings in a configuration file.
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1101
The file must be placed into the same directory as the scope's normal
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1102
configuration file, with the name `<scope-name>-settings.ini`. For example, for a scope with ID `com.acme.myscope`,
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1103
the normal configuration file is `com.acme.myscope.ini`, and the settings definition file is
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1104
`com.acme.myscope-settings.ini`. Both files must be installed in the same directory (together with the scope's `.so` file).
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1105
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1106
The shell constructs a user interface from the settings definitions. The user can change settings via that UI.
1107
The scope can retrieve the actual setting values at run time (see \ref read_settings).
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1108
1109
The following types are supported for settings:
1110
1111
<ul>
1112
<li>`string` - a string value
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1113
<li>`number` - a numeric value (integer or floating point)
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1114
<li>`boolean` - `true` or `false`
1115
<li>`list` - a list of alternatives to choose from (single-choice)
1116
</ul>
1117
1118
It is possible to optionally define a default value for each setting.
1119
1120
Here are the contents of an example definition file:
1121
~~~
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1122
[location]
1123
type = string
1124
defaultValue = London
1125
displayName = Location
1126
1127
[distanceUnit]
1128
type = list
1129
defaultValue = 1
1130
displayName = Distance Unit
1131
displayName[de] = Entfernungseinheit
1132
displayValues = Kilometers;Miles
1133
displayValues[de] = Kilometer;Meilen
1134
1135
[age]
1136
type = number
1137
defaultValue = 23
1138
displayName = Age
1139
1140
[enabled]
1141
type = boolean
1142
defaultValue = true
1143
displayName = Enabled
1144
1145
# Setting without a default value
1146
[color]
1147
type = string
1148
displayName = Color
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1149
~~~
1150
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1151
The file must contain a group for each setting.
1152
The order of the groups determines the display order for the user interface
1153
that is constructed by the shell. The group name is the ID of the corresponding setting.
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1154
1155
Each setting definition must contain at least the following mandatory definitions:
1156
<ul>
1157
<li> `type` - Defines the type of the setting (`string`, `number`, `boolean`, or `list`).
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1158
<li> `displayName` - Defines a display name that is shown for this setting by the shell.
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1159
</ul>
1160
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1161
The defaultValue field is optional. If present, it defines
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1162
a default value that is provided to the scope if the user has not changed anything (or has never used the settings UI
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1163
before using the scope).
1164
It is possible to test for settings that do not have a default value and
1165
were never set by the user (see \ref read_settings).
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1166
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1167
For settings of type `list`, the `displayValues` field is mandatory. It must contain an array
1168
that lists the available choices. If you provide a default value,
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1169
it must be in the range `0..max-1` (where `max` is the number of choices).
1170
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1171
The `displayName` and `displayValues` fields can be localized by appending a locale identifier
1172
in square brackets. If no entry can be found that matches the current locale, the non-localized value
1173
is used.
1174
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1175
\subsubsection read_settings Accessing settings
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1176
1177
The settings that are currently in effect are available to a scope via the unity::scopes::ScopeBase::settings()
1178
and unity::scopes::QueryBase::settings() methods.
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1179
These methods return a unity::scopes::VariantMap with one entry per setting. The map contains an entry for
1180
each setting (using the group name as the key). The lookup value is a unity::scopes::Variant that holds
1181
the current value of the setting.
1182
1183
If a setting has a value, the corresponding entry in the map contains a string (for settings of type `string`,
1184
a boolean (for settings of type `boolean`), or an integer (for settings of type `number` and `list`). (If the user
163.232.1 by Marcus Tomlinson
Missing the word "provide"
1185
did not provide a particular value, but the settings definition provided a default value, the `Variant` contains the
1186
default value.
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1187
1188
If a setting does not have a default value, and the user did not establish a value for the setting, the corresponding
1189
entry is absent from the map.
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1190
1191
When you use settings in your scope implementation, do not cache the values and re-use them
1192
for a different query. If you do, any setting changes made by the user will not take effect until
163.437.3 by Michi Henning
Doc fixes "run time" -> "runtime" for consistency.
1193
your scope is re-started by the runtime. (Because the user cannot know when that happens, this
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1194
can be highly confusing.) Instead, call `settings()` each time you need to use the value
1195
of a setting. That way, your scope will react to any change made by the user as soon as it receives another
1196
query.
1197
163.228.38 by Michi Henning
Changed settings schema to use .ini file instead, called <scope_id>-settings.ini.
1198
Here is an example of how to read the current settings values for the definition in \ref settings_definitions :
1199
1200
~~~
1201
// In your `ScopeBase` or `QueryBase` implementation:
1202
1203
unity::scopes::VariantMap s = settings();  // The settings method is provided by the base class
1204
1205
cout << s["location"].get_string();        // Prints "London" unless the user changed the value
1206
1207
auto it = s.find("color");
1208
if (it != s.end())                         // Setting does not have a default value, need to test
1209
{
1210
    cout << it->second.get_string();       // Prints the user-established value
1211
}
1212
~~~
163.228.26 by Michi Henning
Added semantic check for duplicate setting ids. Added lots of doc to the tutorial.
1213
163.354.5 by Michi Henning
Updated doc and tutorial.
1214
\subsection directories File system access
1215
1216
Scopes that are installed from click packages are subject to confinement and are not allowed
1217
to access most parts of the file system. However, a few locations are available to a scope.
1218
You can access these paths by calling methods on \link unity::scopes::ScopeBase ScopeBase\endlink.
1219
1220
\note Do not call these methods from the constructor of your `ScopeBase` implementation. If you
1221
do, these methods throw `LogicException`. Instead, call them from
1222
\link unity::scopes::ScopeBase::start() start()\endlink or any time thereafter.
1223
1224
\link unity::scopes::ScopeBase::scope_directory() scope_directory()\endlink returns the path of the installation
1225
directory of the scope. This directory contains the scope's `.so` and `.ini` files, plus whatever other
1226
files you decide to package with your scope. The scope has read-only permission for this directory.
1227
1228
\link unity::scopes::ScopeBase::cache_directory() cache_directory()\endlink returns the path of a
1229
directory that is (exclusively) writable for the scope. You can use this directory to store
1230
persistent information, such as a cache of results.
1231
1232
\link unity::scopes::ScopeBase::app_directory() app_directory()\endlink returns the path of a
1233
read-only directory. If the scope is packaged together with an app, the app has permission to write
1234
files in this location, that is, this directory can be used make information provided by the app
1235
available to the scope (but not vice versa).
1236
1237
\link unity::scopes::ScopeBase::tmp_directory() tmp_directory()\endlink returns the path of a
1238
read-only directory that is (exclusively) writable for the scope. This directory is periodically
1239
cleaned of unused files. The exact amount of time may vary, but is on the order of a few hours.
1240
The directory is also cleaned during reboot.
1241
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1242
\subsection online_accounts Online Accounts
1243
1244
A scope may require access to an online account in order to evaluate particular results, perform certain actions, or
1245
perhaps even operate at all. The following section describes how to use online account services from your scope.
1246
1247
\subsubsection oa_step1 Step 1: Update Apparmor manifest.
1248
1249
Firstly, in order for your scope to be granted access to the online accounts backend, the "accounts" policy group needs
1250
to be added to your Apparmor manifest file, as follows:
1251
1252
\paragraph oa_apparmor Example Apparmor manifest file:
1253
\code
1254
{
1255
    "template": "ubuntu-scope-network",
1256
    "policy_groups": [
1257
        "accounts"
1258
    ],
1259
    "policy_version": 1.2
1260
}
1261
\endcode
1262
1263
\subsubsection oa_step2 Step 2: Account service configuration.
1264
1265
Scopes access accounts at a service level (E.g. YouTube service under a Google account, Ubuntu Store service under an
1266
Ubuntu One account, etc.), therefore each scope must provide some config to specify its account service requirements.
1267
163.316.22 by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled
1268
There are 2 additional files that a scope must supply:
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1269
1. A .service file to specify a method of accessing its particular account provider.
163.316.22 by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled
1270
2. A .application file to link one or more services to your scope.
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1271
1272
\paragraph oa_service Example .service file:
1273
\code
1274
<?xml version="1.0" encoding="UTF-8"?>
1275
<service id="com.ubuntu.scopes.youtube_youtube">
1276
  <type>sharing</type>
1277
  <icon>youtube</icon>
1278
  <name>YouTube</name>
1279
  <provider>google</provider>
1280
  <translations>unity-scope-youtube</translations>
1281
  <template>
1282
    <group name="auth">
1283
      <setting name="method">oauth2</setting>
1284
      <setting name="mechanism">web_server</setting>
1285
      <group name="oauth2">
1286
        <group name="web_server">
1287
          <setting name="Host">accounts.google.com</setting>
1288
          <setting name="AuthPath">o/oauth2/auth?access_type=offline</setting>
1289
          <setting name="TokenPath">o/oauth2/token</setting>
1290
          <setting name="RedirectUri">https://wiki.ubuntu.com/</setting>
1291
          <setting name="ResponseType">code</setting>
1292
          <setting type="as" name="Scope">['https://www.googleapis.com/auth/youtube.readonly']</setting>
1293
          <setting name="ClientId">xxxx</setting>
1294
          <setting name="ClientSecret">xxxx</setting>
1295
          <setting type="as" name="AllowedSchemes">['https','http']</setting>
1296
        </group>
1297
      </group>
1298
    </group>
1299
  </template>
1300
</service>
1301
\endcode
1302
1303
\paragraph oa_application Example .application file:
1304
\code
1305
<?xml version="1.0" encoding="UTF-8"?>
1306
<application id="com.ubuntu.scopes.youtube_youtube">
1307
  <description>YouTube</description>
163.316.22 by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled
1308
  <desktop-entry>com.ubuntu.scopes.youtube_youtube.desktop</desktop-entry>
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1309
  <services>
1310
    <service id="com.ubuntu.scopes.youtube_youtube">
1311
      <description>Watch your favorite YouTube videos</description>
1312
    </service>
1313
  </services>
1314
</application>
1315
\endcode
1316
1317
\subsubsection oa_step3 Step 3: Update Click manifest.
1318
163.316.22 by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled
1319
Now that we have added the new files from the previous step to our project, we need to update our click manifest file to include
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1320
them:
1321
1322
\paragraph oa_click Example Click manifest file:
1323
\code
1324
{
1325
    "description": "YouTube scope",
1326
    "framework": "ubuntu-sdk-14.10-dev2",
1327
    "architecture": "armhf",
1328
    "hooks": {
1329
        "youtube": {
1330
            "scope": "youtube",
1331
            "apparmor": "apparmor.json",
1332
            "account-application": "youtube.application",
163.316.22 by Marcus Tomlinson
Create a desktop file for a scope when it is installed, and remove it when uninstalled
1333
            "account-service": "youtube.service"
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1334
        }
1335
    },
1336
    "icon": "youtube/icon.png",
1337
    "maintainer": "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>",
1338
    "name": "com.ubuntu.scopes.youtube",
1339
    "title": "YouTube scope",
1340
    "version": "1.0.12"
1341
}
1342
\endcode
1343
1344
\subsubsection oa_step4 Step 4: Utilize the OnlineAccountClient class.
1345
163.316.21 by Marcus Tomlinson
Some more tutorial.dox clean up
1346
Finally, we can access online account services from within our scope implementation.
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1347
1348
The first thing we need to do is instantiate a unity::scopes::OnlineAccountClient object. On construction we must
1349
specify our account service name, service type, and provider name (These correspond to the values of the "service_id",
1350
"type", and "provider" entries in your .service file).
1351
359.2.2 by Alberto Mardegan
Tests, version and docs
1352
The constructor accepts a fourth optional parameter which can be used to specify a dictionary of authentication data,
1353
whose contents will complement (or override) those authentication parameters specified in the `<template>` element of
1354
the \link oa_service `.service` file\endlink. It can be used in those rare cases where the authentication parameters are
1355
known only at runtime.
1356
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1357
Via this object we can get the statuses of all account services, set a callback for status updates, and register
163.316.21 by Marcus Tomlinson
Some more tutorial.dox clean up
1358
results and widgets that require authorization (See: unity::scopes::OnlineAccountClient class documentation for more
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1359
detail).
1360
163.316.21 by Marcus Tomlinson
Some more tutorial.dox clean up
1361
Here's a simple example of how one could return a "Log-in" result to the dash (Selecting this result from the dash will
1362
trigger an authorization request to the user before executing one of the 2 post-login actions):
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1363
163.316.21 by Marcus Tomlinson
Some more tutorial.dox clean up
1364
\paragraph oa_usage Example OnlineAccountClient usage:
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1365
\code
1366
void Query::run(unity::scopes::SearchReplyProxy const& reply)
1367
{
163.316.21 by Marcus Tomlinson
Some more tutorial.dox clean up
1368
    // Instantiate a unity::scopes::OnlineAccountClient object
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1369
    unity::scopes::OnlineAccountClient oa_client("com.ubuntu.scopes.youtube_youtube", "sharing", "google");
163.316.20 by Marcus Tomlinson
Updated tutorial.dox with more detail on example OnlineAccountClient usage
1370
163.316.21 by Marcus Tomlinson
Some more tutorial.dox clean up
1371
    // Check if our service is authenticated under at least one account
163.316.20 by Marcus Tomlinson
Updated tutorial.dox with more detail on example OnlineAccountClient usage
1372
    bool service_authenticated = false;
1373
    for (auto const& status : oa_client.get_service_statuses())
1374
    {
1375
        if (status.service_authenticated)
1376
        {
1377
            service_authenticated = true;
1378
            break;
1379
        }
1380
    }
1381
1382
    // If our service is not authenticated, return a "Log-in" result
1383
    if (!service_authenticated)
1384
    {
1385
        auto cat = reply->register_category("youtube_login", "", "");
1386
        unity::scopes::CategorisedResult res(cat);
1387
        res.set_title("Log-in to YouTube");
1388
1389
        oa_client.register_account_login_item(res,
1390
                                              query(),
1391
                                              unity::scopes::OnlineAccountClient::InvalidateResults,
1392
                                              unity::scopes::OnlineAccountClient::DoNothing);
1393
        reply->push(res);
1394
    }
163.316.14 by Marcus Tomlinson
Added "Online Accounts" section to tutorial.dox
1395
}
1396
\endcode
1397
163.98.1 by Pawel Stolowski
Minor additions to the tutorial.
1398
\subsection scopetesting Testing
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1399
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1400
The Unity Scopes API provides testing helpers based on the well-known and established testing frameworks,
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1401
<a href="https://code.google.com/p/googletest/">googletest</a> and <a href="https://code.google.com/p/googlemock/">googlemock</a>.
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1402
Please see the respective documentation of these framework for general information on how to use them.
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1403
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1404
The testing helper classes are in the unity::scopes::testing namespace. The most important ones are:
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1405
<ul>
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1406
<li>unity::scopes::testing::TypedScopeFixture - A template class that takes your scope class name as a template argument
1407
and creates a test fixture that can be used in tests.
1408
<li>unity::scopes::testing::MockSearchReply - A mock of unity::scopes::SearchReply that makes it possible to intercept
1409
responses to search request sent from the scope to a client, so you can test if your scope returns the expected data.
1410
<li>unity::scopes::testing::MockPreviewReply - A mock of unity::scopes::PreviewReply that makes it possible to
1411
intercept and test responses to preview request sent from the scope to a client.
1412
<li>unity::scopes::testing::Result - A simple Result class derived from unity::scopes::Result that provides a default constructor,
1413
so you can create dummy results (without attributes) for testing purposes.
1414
<li>unity::scopes::testing::category - A simple class derived from unity::scopes::Category that makes it possible to create
1415
dummy categories (which otherwise would require an instance of \link unity::scopes::SearchReply SearchReply\endlink and a call to
1416
\link unity::scopes::SearchReply::register_category register_category()\endlink).
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1417
</ul>
1418
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1419
Here is a test that checks if `MyScope` calls appropriate methods of unity::scopes::SearchReply. Note
1420
that the test only checks that the correct methods are called and uses `_` matchers that match any value.
1421
For a proper test, you will need to substitute values appropriate for your scope.
1422
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1423
\code{.cpp}
163.258.1 by Michi Henning
Refactored scoperunner and ScopeLoader. ScopeLoader
1424
typedef unity::scopes::testing::TypedScopeFixture<MyScope> TestScopeFixture;
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1425
using namespace ::testing;
1426
163.258.1 by Michi Henning
Refactored scoperunner and ScopeLoader. ScopeLoader
1427
TEST_F(TestScopeFixture, search_results)
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1428
{
1429
    const unity::scopes::CategoryRenderer renderer;
1430
1431
    NiceMock<unity::scopes::testing::MockSearchReply> reply;
1432
    EXPECT_CALL(reply, register_departments(_, _)).Times(1);
1433
    EXPECT_CALL(reply, register_category(_, _, _, _))
1434
            .Times(1)
1435
            .WillOnce(
1436
                Return(
1437
                    unity::scopes::Category::SCPtr(new unity::scopes::testing::Category("id", "title", "icon", renderer))
1438
                )
1439
            );
163.147.4 by Pawel Stolowski
Updated tutorial.
1440
    EXPECT_CALL(reply, push(Matcher<unity::scopes::Annotation const&>(_)))
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1441
            .Times(1)
1442
            .WillOnce(Return(true));
163.147.4 by Pawel Stolowski
Updated tutorial.
1443
    EXPECT_CALL(reply, push(Matcher<unity::scopes::CategorisedResult const&>(_)))
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1444
            .Times(1)
1445
            .WillOnce(Return(true));
1446
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1447
    // note: this is a std::shared_ptr with empty deleter
1448
    unity::scopes::SearchReplyProxy reply_proxy(&reply, [](unity::scopes::SearchReplyBase*) {});
163.83.7 by Pawel Stolowski
Added testing section to the tutorial.
1449
1450
    unity::scopes::CannedQuery query(scope_id, "", "");
1451
    unity::scopes::SearchMetadata meta_data("en_EN", "phone");
1452
1453
    auto search_query = scope->search(query, meta_data);
1454
    ASSERT_NE(nullptr, search_query);
1455
    search_query->run(reply_proxy);
1456
}
1457
\endcode
163.98.3 by Pawel Stolowski
Added stub section for deployment.
1458
1459
\subsection deployment Deployment
1460
163.98.15 by Michal Hruby
Add some basic information on getting the template and deployment, to be completed
1461
Installing a scope is as simple as running `make install` when using the scope
1462
template. You might need to restart the global scope registry when a new scope
163.98.18 by James Henstridge
Use a verbatim block for the restart command.
1463
is installed by running:
1464
1465
\verbatim
1466
restart scope-registry
1467
\endverbatim
163.98.15 by Michal Hruby
Add some basic information on getting the template and deployment, to be completed
1468
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1469
Scopes are installed under one of the "scopes directories"
163.98.16 by James Henstridge
Flesh out the deployment section.
1470
scanned by the scope registry.  Currently these default to:
1471
163.98.17 by James Henstridge
Fix bullet list and comment out note about click package install
1472
<ul>
1473
<li>/usr/lib/${arch}/unity-scopes</li>
1474
<li>/custom/lib/${arch}/unity-scopes</li>
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1475
<li>$HOME/.local/share/unity-scopes</li>
163.98.17 by James Henstridge
Fix bullet list and comment out note about click package install
1476
</ul>
163.98.16 by James Henstridge
Flesh out the deployment section.
1477
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1478
The `/usr/lib` directory is for scopes that are pre-installed by Canonical.
1479
The `/custom/lib` directory is for scopes that pre-installed by OEMs.
1480
The `$HOME/.local` directory is for scopes that are installed from click packages.
1481
1482
Individual scopes are installed into subdirectories of these
1483
installation directories. The name of the subdirectory containing
1484
a scope's `.ini` and `.so` files can be anything but, to avoid name clashes,
1485
we strongly suggest something that is unique, such as `com.canonical.scopes.scopename`.
1486
At a minimum, the directory structure must contain the following:
163.98.16 by James Henstridge
Flesh out the deployment section.
1487
1488
    -+- ${scopesdir}
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1489
     `-+- subdirectory
163.98.16 by James Henstridge
Flesh out the deployment section.
1490
       |--- scopename.ini
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1491
       `--- <library>.so
163.98.16 by James Henstridge
Flesh out the deployment section.
1492
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1493
That is, each subdirectory must contain a scope `.ini` file and a shared library containing the
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1494
scope code. You are free to ship additional data in this
1495
directory, such as a settings definition file (if your scope uses settings) or icon files
1496
and screenshots.
163.98.16 by James Henstridge
Flesh out the deployment section.
1497
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1498
The name of the scope's `.ini` file _must_ be a unique ID for the scope. We _strongly_
1499
suggest to use a unique identifier, such as `com.canonical.scopes.scopename`, to avoid
1500
clashes with scopes created by other developers.
1501
163.142.78 by Michal Hruby
Update tutorial
1502
The name of of the scope's `.so` file can be `libscopename.so`, `scopename.so`, or simply `scope.so`. For example,
1503
for a scope named `Fred`, the names `libFred.so`, `Fred.so`, and `scope.so` are acceptable. (No other library
1504
names are valid.)
1505
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1506
The scope `.ini` file uses the standard `.ini` file format, with the
163.98.16 by James Henstridge
Flesh out the deployment section.
1507
following keys:
1508
1509
    [ScopeConfig]
1510
    DisplayName = human readable name of scope
1511
    Description = description of scope
1512
    Author = Author
163.350.1 by Michi Henning
Added Version attribute to Scope.ini and scope metadata.
1513
    Version = 1
163.98.16 by James Henstridge
Flesh out the deployment section.
1514
    Icon = path to icon representing the scope
1515
    Art = path to screenshot of the scope
1516
    SearchHint = hint text displayed to user when viewing scope
1517
    HotKey =
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1518
    ResultsTtlType = None, Small, Medium, or Large
163.374.2 by Marcus Tomlinson
Renamed all occurrences of "tag" with "keyword"
1519
    Keywords =
163.414.2 by Michi Henning
Review comments from Marcus.
1520
    IsAggregator = true or false
275.2.1 by Michi Henning
Documented missing config items.
1521
    IdleTimeout = idle timeout in seconds
1522
    LocationDataNeeded = true or false
1523
    ScopeRunner = path_to_scope_runner args... %R %S
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1524
1525
    [Appearance]
163.142.78 by Michal Hruby
Update tutorial
1526
    ForegroundColor = default text color (defaults to theme-provided foreground color)
1527
    BackgroundColor = color of scope background (default is transparent)
163.245.1 by Michal Hruby
Updated docs
1528
    ShapeImages = whether to use Ubuntu-shape for all cards and artwork (defaults to true)
1529
    PreviewButtonColor = color of preview buttons (defaults to theme-provided color)
163.253.1 by Michal Hruby
Added one more appearance attribute
1530
    LogoOverlayColor = color for the overlay in scopes overview (defaults to semi-transparent black)
163.245.1 by Michal Hruby
Updated docs
1531
    PageHeader.Logo = image containing scope's logo
1532
    PageHeader.ForegroundColor = default header text color (defaults to the overall foreground color)
1533
    PageHeader.Background = background scheme of the header
1534
    PageHeader.DividerColor = color of the header divider
1535
    PageHeader.NavigationBackground = background scheme of the navigation bar
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1536
275.2.1 by Michi Henning
Documented missing config items.
1537
The `ScopeConfig` group is mandatory. The information in this group makes the scope known to the registry.
1538
In addition, this information controls how the scope appears in the "Scopes" scope.
1539
1540
The `ScopeConfig` group must contain settings for at least `DisplayName`, `Description`, and `Author`.
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1541
`DisplayName` and `Description` can (and should) be localized. For example:
1542
163.258.3 by Michi Henning
Completed support for cache_directory() accessor.
1543
`Description[de_DE] = Fu&szlig;ballergebnisse`
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1544
163.350.1 by Michi Henning
Added Version attribute to Scope.ini and scope metadata.
1545
The `Version` key is optional, but we strongly recommend that you set it.
1546
If the behavior of your scope changes in any way that is visible to the query source
1547
(such having added or removed a result attribute), you should increment the version number.
163.350.3 by Michi Henning
Fixed typos in comments and doc.
1548
This allows an aggregating scope to adjust its behavior according to which version of
163.350.1 by Michi Henning
Added Version attribute to Scope.ini and scope metadata.
1549
your scope is installed.
1550
If not set, the default value is 0. You can set the value to any integer >= 1.
1551
163.414.1 by Michi Henning
Updated doc for scope.ini keys.
1552
The `SearchHint` key provides text that may be shown by the UI, such as "Enter a city name".
1553
1554
The `Keywords` key is optional, but we recommend that you use it. Keywords are used by aggregators
1555
to collect results from scopes of similar type (E.g. The Music scope will aggregate scopes with the
1556
keyword "music", and so on). The value of `Keywords` should specify a list of keywords your scope
1557
falls under. This value must be a semicolon separated list (E.g. `Keywords = music;video`).
1558
163.414.2 by Michi Henning
Review comments from Marcus.
1559
The `IsAggregator` key must be set to `true` for aggregating scopes. The default value is `false`.
1560
275.2.1 by Michi Henning
Documented missing config items.
1561
The `IdleTimeout` key controls how long a scope can remain idle before it is told to stop by the registry (or
1562
killed if it does not stop within 4 seconds). The default idle timeout is 40 seconds, meaning that a
163.480.1 by Marcus Tomlinson
Be much stricter on idle timeout (1s to 5min). Not only are scopes currently allowed to set very very large timeouts, we seem to allow disabling of the timeout entirely (a value of -1) :/
1563
scope will be told to stop if no query was sent to it for that amount of time. Only values in the range 1 to
1564
300 seconds are accepted.
275.2.1 by Michi Henning
Documented missing config items.
1565
163.414.1 by Michi Henning
Updated doc for scope.ini keys.
1566
`ResultTtl` determines how long results should be cached by the UI before they are considered "stale"
1567
and should be refreshed. `None` indicates that results remain valid indefinitely; `Small` indicates
1568
results are valid for around a minute; `Medium` indicates that results are valid for a few minutes;
1569
`Large` indicates that results remain valid for around an hour.
1570
275.2.1 by Michi Henning
Documented missing config items.
1571
`LocationDataNeeded` should be set to `true` if the scope requires location data. In that case, the
1572
\link unity::scopes::SearchMetadata SearchMetadata\endlink provides access to
1573
\link unity::scopes::Location Location\endlink information
1574
(assuming the user has granted location permission to the scope). If not set, the default value is `false`.
1575
1576
The `Scoperunner` key defines a command line to be executed when the scope is started by the registry.
1577
Typically, scopes do not need to change this setting. It is provided mainly to allow scopes implemented
1578
in languages other than C++ to be started, as well as for debugging.
1579
For example, the following setting causes a scope to be run under `gdb`:
1580
1581
`ScopeRunner = /usr/bin/gdb --ex run --args /usr/lib/x86_64-linux-gnu/unity-scopes/scoperunner %R %S`
1582
1583
The `%R` expands to the path to the `Runtime.ini` config file, and `%S` expands to the scope's `.ini` file.
1584
1585
The `Appearance` group and all keys within it are optional and can be used to customize the look of the scope.
163.414.1 by Michi Henning
Updated doc for scope.ini keys.
1586
Some of the `Appearance` keys (such as `PageHeader.Background`) require background scheme URIs.
1587
Valid URIs for these keys include:
163.245.1 by Michal Hruby
Updated docs
1588
1589
<ul>
1590
<li>color:///\#aarrggbb</li>
1591
<li>color:///black</li>
1592
<li>gradient:///\#aarrggbb/\#aarrggbb</li>
1593
<li>/absolute/path/to/image</li>
1594
<li>http://remote-server.com/path/to/image</li>
1595
</ul>
163.98.6 by Michal Hruby
Added section on scope-tool
1596
163.402.4 by Marcus Tomlinson
Add reference to keywords doc in scope config section as well
1597
\note Please refer to the <a href="https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/">Scope Keywords</a>
1598
tutorial document for more detail on using keywords in your scope.
1599
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1600
\subsection scopetool The scope tool
1601
163.437.4 by Michi Henning
Fixed typos.
1602
The Unity Scope Tool is a stand-alone rendering tool that allows you
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1603
to see how the dash will render your scope.
1604
1605
You can install the tool from the Ubuntu archive using:
163.98.14 by Pawel Stolowski
Use verbatim.
1606
\verbatim
1607
sudo apt-get install unity-scope-tool
1608
\endverbatim
163.98.6 by Michal Hruby
Added section on scope-tool
1609
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1610
After installation, you can run the scope-tool with a parameter specifying the
1611
path to your scope configuration file (for example `unity-scope-tool ~/dev/myscope/build/myscope.ini`).
1612
If a binary for your scope can be found in the same
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1613
directory, the scope-tool
1614
displays surfacing and search results provided by your scope, and it allows you to
1615
perform searches, invoke previews, and perform actions within previews.
163.98.6 by Michal Hruby
Added section on scope-tool
1616
163.181.2 by Michi Henning
Updated doc for new library names. Minor style fixes in the doc.
1617
Note that the scope-tool uses the same rendering mechanism as Unity
1618
itself and, therefore, what you see in the scope-tool is what you get in Unity.
163.315.1 by Michi Henning
Lots of doc fixes and updates.
1619
The tool can also be used to fine-tune category definitions, as it allows you
1620
to manipulate the definitions on the fly. Once you are satisfied with the result,
163.98.7 by Michal Hruby
A bit more
1621
you can just copy the JSON definition back into your scope
1622
(see unity::scopes::CategoryRenderer::CategoryRenderer()).
163.98.6 by Michal Hruby
Added section on scope-tool
1623
1624
The scope-tool supports a few command line arguments:
163.437.4 by Michi Henning
Fixed typos.
1625
\arg By default (without any arguments) it will communicate with all scopes
163.98.6 by Michal Hruby
Added section on scope-tool
1626
installed on the system and available on the smart scopes server.
1627
\arg When a path to a scope configuration file is provided, only that scope is
1628
initialized, but you can either pass multiple configuration files or
1629
the `--include-system-scopes` / `--include-server-scopes` option to allow
1630
development of aggregating scopes.
1631
64.1.1 by Pawel Stolowski
First cut at scopes tutorial.
1632
*/