49
Scope development :)

Ubuntu scope development

Embed Size (px)

Citation preview

Page 1: Ubuntu scope development

Scope development :)

Page 2: Ubuntu scope development

Agenda

1 What are scopes? Terminology 5 Building blocks (back-end)

2 Scope in detail

3 Tools

4 Building blocks (front-end)

6 Hands-on

Page 3: Ubuntu scope development

What are scopes? Terminology

Page 4: Ubuntu scope development

What do scopes look like?

Page 5: Ubuntu scope development

Scopes are a a UI toolkit to present local or remote content and services in the home screen

Make you content and services easy to discover:

● Scopes are easy to find and favourite as a new home screen

● Scopes dont fight for user attention, related content :○ Search for an artist in Music to see songs

in your phone, concerts near you or buy their new album

Scopes are very easy to build, the only thing you need to get started is any kind of web api.

Scopes | A New UI ParadigmA user experience where content is front and center

Page 6: Ubuntu scope development

Scopes are fast and engaging Scopes are a fast and engaging way to embed your services in Ubuntu

Indian Today(Neaby)

Time of Indian(News)

Indian Video content(Video)

Page 7: Ubuntu scope development

Surface you content on the homescreenDefault aggregating scopes can put your content where it matters

Relevant sources displayed together

Users can discover your service via search

The user can easily configure what to see

Page 8: Ubuntu scope development

Scopes in detail

Page 9: Ubuntu scope development

● A scope is a dedicated search engine that responds to queries, or surfacing about content

● A scope is passive, runs on demand only

● Produces query results● Responds to preview and/or

activation requests on results● A scope can customize visual

appearance or results (order, layout, etc.)

What is a scope really about technically?

Page 10: Ubuntu scope development

Scopes data flow

Page 11: Ubuntu scope development

Aggregated scope

A scope can call a scope, and a scope can aggregate data from any data sources, including other scopes

Page 12: Ubuntu scope development

Process life cycle

● scoperegistry started by upstart, runs permanently

● scoperunners started by registry on demand

● scoperunners exit after 40 seconds of idle time

Page 13: Ubuntu scope development

Registry

● White pages lookup service○ Provides list of all scopes (local and

remote)○ Provides metadata for each scope

(name, description, author, etc.)○ Provides invocation handle for each

scope● Starts and stops scoperunners● Monitors installation files for

added/deleted scopes

Page 14: Ubuntu scope development

Tools

Page 15: Ubuntu scope development

IDE● Ubuntu SDK to cross-build a scope to armhf and click package it

CLI● cmake & make● unity-scope-tool● phablet-screenshot● http://blog.csdn.net/ubuntutouch/article/details/40651093

Environment/host● Utopic 14.10, develop against latest APIs● click chroot or sbuild to cross build on your work machine● armhf device (i.e. Nexus 4, Nexus 7, Chromebook)● http://blog.csdn.net/ubuntutouch/article/details/38395635

Tools

Page 16: Ubuntu scope development

Building blocks (front-end)

Page 17: Ubuntu scope development

Categories

● Every result has a category● Categories group results into named groups● The shell renders categories according to a JSON

definition that controls aspects of the display● Results are rendered in the order in which they are

pushed, grouped by category. The order in which results are pushed determines the order of the categories. Every time a result with a new category is pushed, the shell creates a new group (in top-to-bottom or left-to-right order)

● The shell may choose to show categories collapsed if they contain more than one row of results (depending on the renderer)

Page 18: Ubuntu scope development

Categories vertical templateconst static string CAT_RENDERER { R"( { "schema_version" : 1, "template" : { "category-layout" : "grid", "card-layout": "vertical", "card-size" : "large", "card-background": "#00FF00" }, "components" : { "title" : "title", "art" : "art", "subtitle": "subtitle", "mascot": "mascot", "emblem": "emblem", "summary": "summary", "overlay-color": "overlay-color", "attributes": { "field": "attributes", "max-count": 2 } } } )" };

Page 19: Ubuntu scope development

Categories horizontal templateconst static string CAT_RENDERER { R"( { "schema_version" : 1, "template" : { "category-layout" : "grid", "card-layout": "horizontal", "card-size" : "large", "card-background": "#00FF00" }, "components" : { "title" : "title", "art" : "art", "subtitle": "subtitle", "mascot": "mascot", "emblem": "emblem", "summary": "summary", "overlay-color": "overlay-color", "attributes": { "field": "attributes", "max-count": 2 } } } )" };

Page 20: Ubuntu scope development

Cards

Sizes● small● medium● large

Card-Layout● vertical● horizontal

Overlay

Layouts● grid● carousel● v-journal

http://goo.gl/75s3Ln - should not be treated as documentation, but a nice referencehttp://goo.gl/1VXa0l -a good tutorial for customization and branding of your scope

Building blocks | front-end

Page 21: Ubuntu scope development

Category layouts

Page 22: Ubuntu scope development

Widgets● audio

● video

● image

● gallery

● header

● actions

● progress

● text

● rating-input

● reviews

● table

Building blocks | front-end

http://developer.ubuntu.com/api/scopes/sdk-14.04/preview_20widget_20types/

Page 23: Ubuntu scope development

Building blocks (back-end)

Page 24: Ubuntu scope development

Scope source constitutes of the following classes

● scope - extends unity::scopes::ScopeBase● query - extends unity::scopes::SearchQueryBase● preview - extends unity::scopes::PreviewQueryBase

Most important classes

● CannedQuery - contains query, department id, filter state● PreviewReplyProxy - feeds back the results

Building blocks | back-end

http://developer.ubuntu.com/api/scopes/sdk-14.10/

Page 25: Ubuntu scope development

Scope - directories

● Scope directorystd::string unity::scopes::ScopeBase::scope_directory()/opt/click.ubuntu.com/com.ubuntu.developer.liu-xiao-guo.dianping/0.1/dianping

● Scope cachestd::string unity::scopes::ScopeBase::cache_directory()/home/phablet/.local/share/unity-scopes/leaf-net/com.ubuntu.developer.liu-xiao-guo.dianping

● Scope tmp directorystd::string unity::scopes::ScopeBase::tmp_directory()/run/user/32011/scopes/leaf-net/com.ubuntu.developer.liu-xiao-guo.dianping_dianping

Page 26: Ubuntu scope development

Scope - search metadata

class SearchMetadata : public QueryMetadata {

public:

int cardinality() const;

Location location() const;

bool has_location() const;

...

};

class QueryMetadata {

public:

std::string locale() const; // "zh_CN"

std::string form_factor() const; // "phone"

...

}

void Query::run(sc::SearchReplyProxy const& reply) { auto metadata = search_metadata();

}

Page 27: Ubuntu scope development

● The query string may be the empty string when scope is started

● UI is asking your scope to produce default results that are shown in what is known as surfacing mode

● Show something when scope is started○ Music scope could be “Popular songs”○ Weather scope could “current location”

weather○ A developer has to decide what to show

Query - surfacing mode

Page 28: Ubuntu scope development

Query - department scope

● A way for users to navigate the data sources/channels exposed by the scope

● A department may have optional sub-department

● Each department has an unique id to identify it

● Department id info is used to generate the request uri

● Display will be matched with the returned results

Page 29: Ubuntu scope development

Query - department scope with filter

● A way for users to provide multiple options to select

Page 30: Ubuntu scope development

Query - CannedQuery

class CannedQuery final {

public:

string scope_id() const;

string department_id() const;

string query_string() const;

string to_uri() const;

static CannedQuery from_uri(string const& uri);

// …

};

● CannedQuery() provides accessors for query details and to/from URI conversion (scope:// schema)

● Also provides constructor and modifiers, so you can create a query

void Query::run( sc::SearchReplyProxy const& reply ) { CannedQuery cannedQuery = query();}

Page 31: Ubuntu scope development

Query - register categories

class SearchReply : public virtual Reply

{

public:

virtual Category::SCPtr register_category(

std::string const& id, //must be unique!

std::string const& title,

std::string const& icon,

CategoryRenderer const& renderer_template = CategoryRenderer()) = 0;

virtual bool push(CategorisedResult const& result) = 0;

// ...

};

CategoryRenderer rdrCarousel(CR_CAROUSEL_TEMPLATE);

auto carousel = reply->register_category

("dianpingcarousel", title.toStdString(), "",

rdrCarousel);

Page 32: Ubuntu scope development

Query - push results 1/2

class Result { // abstract base class

public:

void set_uri(std::string const& uri); // mandatory

void set_title(std::string const& title);

void set_art(std::string const& image);

Variant& operator[](std::string const& key);

Variant const& operator[](std::string const& key) const;

bool contains(std::string const& key) const;

// ...

};

class CategorisedResult: public Result{public: explicit CategorisedResult(Category::SCPtr category); void set_category(Category::SCPtr category); Category::SCPtr category() const;};

Page 33: Ubuntu scope development

Query - push results 2/2

CategorisedResult catres(carousel);

catres.set_uri(business_url.toStdString());

catres.set_dnd_uri(business_url.toStdString()); catres.set_title(name.toStdString());

catres["subtitle"] = address.toStdString();

catres["summary"] = summary.toStdString();

catres.set_art(photo_url.toStdString());

catres["address"] = Variant(address.toStdString());

catres["telephone"] = Variant(telephone.toStdString());

//push the categorized result to the client

if (!reply->push(catres)) {

break; // false from push() means search waas cancelled

}

The category order depends on the order of the pushing CategorisedResult

Page 34: Ubuntu scope development

● Previews support 1-, 2-, and 3- column layout● The dash picks what is appropriate for the device● Each column contains one or more display widgets● Widgets are displayed in the order in which they are added to columns.● Widgets come in a number of types:

- audio, video, image, gallery, header, actions, progress, test, rating-input, reviews, expandable

- Each widget type has a number of attributes that depend on the widget type

- E.g., a text widget has a mandatory string attribute named “text” and an optional string attribute named “title”

- Valid widget types and attributes are described in the doc

Preview - layout

Page 35: Ubuntu scope development

Preview layout (cont.)void Preview::run(unity::scopes::PreviewReplyProxy const& reply){ ColumnLayout layout1col(1), layout2col(2);

layout1col.add_column({"headerId", "artId", "infoId", "telId", "actionsId"}); layout2col.add_column({"artId", "headerId"}); layout2col.add_column({"infoId", "telId", "actionsId"});

// Push the layouts into the PreviewReplyProxy intance, thus making them // available for use in Preview diplay reply->register_layout({layout1col, layout2col});

//Create some widgets PreviewWidget w_header("headerId", "header"); w_header.add_attribute_mapping("title", "title"); … PreviewWidget w_tel("telId", "text"); w_tel.add_attribute_mapping("text", "telephone");

Result result = PreviewQueryBase::result(); QString urlString(result["uri"].get_string().c_str()); // Bundle out widgets as required into a PreviewWidgetList PreviewWidgetList widgets({w_header, w_art, w_info, w_tel, w_actions}); // And push them to the PreviewReplyProxy as needed for use in the preview reply->push(widgets);}

Page 36: Ubuntu scope development

Preview - widget initialization

● Four ways to initialize widget attributes:○ Set attribute directly and push widget○ Push value to widget (new value

overrides any previous value and updates display)

○ Map result attributes to widget attributes○ Construct entire widget from a JSON

string

Page 37: Ubuntu scope development

Preview - widget direct attr initialization

// Widget for “summary_wgt” of type text

PreviewWidget description(“summary_wgt”, “text”);

Variant v(“This is a description”);

Description.add_attribute_value(v);

reply->push({ description });

● Variant is a thin wrapper around boost::variant with much the same functionality

● You can update values, pushing the same attribute several times renders the last-pushed value.

Page 38: Ubuntu scope development

Preview - widget attribute mapping // Widget of type image

PreviewWidget image(“image_wgt”, “image”);

// “art” field of result becomes “source” attribute.

image.add_attribute_mapping(“source”, “art”);

// Widget type header

PreviewWidget header(“header_wgt”, “header”);

// “title” field of result goes into title,

// “subtitle” field of result goes into subtitle.

header.add_attribute_mapping(“title”, “title”);

header.add_attribute_mapping(“subtitle”, “subtitle”);

reply->push({ image, header}); // Pushes both widgets

The first constructor argument links the widget to its column. The second constructor argument sets the type of widget (text, audio, etc.) add_attribute_mapping arranges for the specified widget attribute to be filled by the specified attribute in the result: add_attribute_mapping(widget_attr, result_attr); To pass the corresponding value to the shell for display, call push() on the PreviewReplyProxy:

Page 39: Ubuntu scope development

Preview - pushing into mapped attribute

PreviewWidget description(“summary_wgt”, “text”);\

description.add_attribute_mapping(“title”,

“description_heading”);

description.add_attribute_mapping(“text”, “description”);

reply->push({ description });

reply->push(“description”, Variant(“replacement description”);

● Pushing an attribute directly pushes the attribute into the result, as if the attribute had been set in the result to begin with

● The attribute mapping then maps the result attribute to the widget attribute

Page 40: Ubuntu scope development

Scope .ini file

● The .ini file for a scope must contain a [ScopeConfig] group with at least the following attributes:○ DisplayName○ Description○ Author○ DisplayName and Description can (and should) be

localized.

[ScopeConfig]DisplayName = Sports NewsDisplayName[de] = SportnachrichtenDescription = Breaking news from the world of sportsAuthor = Not MeIcon = URL for icon fileArt = URL for screen shot of the

Page 41: Ubuntu scope development

Scope .ini file (cont.)

● The [Appearance] group of the scope’s .ini file controls basic visual settings:

● [Appearance]● ForegroundColor =● BackgroundColor =● ShapeImages = true or false● CategoryHeaderBackground = URL● PreviewButtonColor =● LogoOverlayColor =● PageHeader.Logo = URL● PageHeader.ForegroundColor =● PageHeader.Background = URL● PageHeader.DividerColor =● PageHeader.NavigationBackground = URL● Color and background specifications can be color names (white)

or URLs

http://developer.ubuntu.com/scopes/guides/scopes-customization-branding/

Page 42: Ubuntu scope development

Scope setting

● Scopes can use persistent settings● Scope author ships a .ini settings definition

that defines which settings exist● The shell constructs a UI for the scope’s

settings● User enters/changes setting values● ScopeBase and QueryBase provide access

to currently-established settings● Very simple types: bool, string, number (int

or float), single-choice pick list

Page 43: Ubuntu scope development

Scope setting definitions

● Setting name: “scope ini file with no extension”-settting.ini data/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini

[location]type = stringdefaultValue = LondondisplayName = Location

[distanceUnit]type = listdefaultValue = 1displayName = Distance UnitdisplayName[de] = EntfernungseinheitdisplayValues = Kilometers;MilesdisplayValues[de] = Kilometer;Meilen

[color]type = stringdisplayName = Color

Page 44: Ubuntu scope development

Scope setting access

The settings() method on QueryBase and ScopeBase returns a dictionary of string-Variant pairs.

// In your ScopeBase or QueryBase implementation:

// (The settings method is provided by the base class.)

unity::scopes::VariantMap s = settings();

// Prints "London" unless the user changed the value

cout << s.at("location”).get_string();

try {

cout << s.at("color").get_string() << endl;

} catch (std::out_of_range) {

// Color not set, no default value defined.

}

Page 45: Ubuntu scope development

Adding keyword to your scopes (1/2)

Adding keywords to your scope in order to improve its discoverability in these searches- Users searching for scopes on the store- Aggregators looking for child scopes

[ScopeConfig]

DisplayName = scopename

Description = description of scope

Author = author

Keywords = videos;

https://developer.ubuntu.com/en/scopes/tutorials/scope-keywords/http://summit.ubuntu.com/uos-1505/meeting/22460/scopes-keywords/

Page 46: Ubuntu scope development

Adding keyword to your scopes (2/2)

Page 47: Ubuntu scope development

● Ubuntu Developer http://developer.ubuntu.com/- Scope http://developer.ubuntu.com/scopes/overview/

● Touch - Ubuntu Wiki https://wiki.ubuntu.com/Touch- Touch/Porting https://wiki.ubuntu.com/Touch/Porting- Touch/Deploying https://wiki.ubuntu.com/Touch/Deploying

● Ubuntu Phone - https://lists.launchpad.net/ubuntu-phone/● Tech support - http://askubuntu.com/● Publish your app: http://developer.ubuntu.com/publish/● Department scope example: http://goo.gl/o5XZxf● Scope tutorials: http://developer.ubuntu.com/scopes/tutorials/● Scopes:https://developer.ubuntu.com/api/scopes/cpp/development/

Page 48: Ubuntu scope development

Hands-on

Page 49: Ubuntu scope development

Questions?

IRC: liuxg | mail: [email protected]