Widget Application
A widget application (or widget) is a specialized application that provides users with a quick view of specific information from the parent application. In addition, the widget can allow the user to access certain features without launching the parent application. Combined with the parent application, your widget can have various features to increase the usability of your application set.
This feature is supported in wearable applications only.
Web widgets are implemented using the Web programming technologies, such as HTML, CSS, and JavaScript; but only a subset of Tizen Web APIs. Web widgets run on wearable devices and are available to users in the widget board, which can be accessed by swiping right on the home screen (watch face).
Figure: Widget board
Web widgets occupy the entire screen to make the most out of the limited screen size. All content in a wearable widget must fit on 1 screen.
Figure: Wearable widgets
Since widgets are loaded on the widget board in the home screen layer, the only kind of interactivity available for the user is tapping. The users can tap an action button or anywhere on the widget screen to perform specified tasks or open the parent application.
Figure: User actions on a widget
Application model
Web widgets use only a subset of HTML, CSS, and DOM APIs available for Web applications. Since a design goal of widgets is to provide a quick view of the widget content to the user, there are some restrictions in the Web widget implementation to prevent unnecessary performance degradation:
- Web widgets cannot use external network resource loading (for example, CSS, JavaScript, and image files).
- The total size of the HTML, CSS, and JavaScript files in the widget is limited to less than 50 Kbytes.
- The image resolution in a widget must be less than 1.5 times the base image resolution of the Web Widget Specification.
- Only JPEG, PNG, and GIF formats are allowed for image files.
You can create a standalone Web widget, with no parent Web application. In this case, the parent Web application is generated automatically by Tizen Studio during packaging. However, this kind of widget is used for development and testing purposes only. To be published in the official site for Tizen applications, Web widgets must be combined with a real parent application.
More than 1 Web widget can be included in a parent Web application, and all widgets and the parent are bundled in 1 package by Tizen Studio. Web widget resources are included in its Web application package. The Tizen platform installs the Web widget when its parent Web application is installed, and uninstalls the Web widget when its parent Web application is uninstalled. The Web widget resources are all removed together with its parent.
Figure: Widget and Web application packaging
As multiple widgets are allowed in a package, each widget must be identified. The Web widget ID must be assigned with its parent Web application ID as a prefix, so the format is as follows:
<Web application ID>.<widget name>
The Web application ID is a combination of the package ID and the name of the Web application:
<package ID>.<Web application name>
The package ID is a random sequence of characters and numbers, which is automatically generated by Tizen Studio, while you must define the Web application and widget name when creating the applications. For example, if you name your Web application foo
and its widget bar
, and Tizen Studio creates the package ID as Zyj5WR
, the Web application ID is Zyj5WR.foo
and the Web widget ID is Zyj5WR.foo.bar
.
Life-cycle
The Tizen framework manages the operational states and life-cycle of the Web widgets: installation, creation, termination, and uninstallation. The following figure illustrates the Web widget’s operational state changes.
Figure: Operational state changes
The Web widget life-cycle proceeds as follows:
-
The user downloads a Web application from an app store, and installs it with its Web widgets on a wearable device.
-
The users selects the widget in the Add Widget menu (by swiping right on the home screen), and the Tizen framework creates an instance of the Web widget and makes it available in the widget board.
-
When the user launches the widget from the widget board, an
onload
event is generated.A
visibilityChange
event is also generated and the value of thevisibilityState
property is set tovisible
. This means that the widget is in operation and its content is displayed on the screen. Whenever a widget is visible, the user can tap the UI screen to invoke specified tasks, such as launching the widget’s parent application. -
While the widget is running:
- The user can suspend the widget by navigating away from the widget UI screen, for example, by rotating the Gear bezel. The
visibilityChange
event is generated and the value of thevisibilityState
property is set tohidden
. The widget content is no longer visible on the UI screen, but the widget instance remains. - By navigating to the widget in the widget board, the user can resume the widget operations. The
visibilityChange
event is generated again, the value of thevisibilityState
property is set tovisible
, and the widget content is displayed on the screen.
Other examples of the actions causing widget visibility changes are switching off the screen or switching the viewport to another application.
- The user can suspend the widget by navigating away from the widget UI screen, for example, by rotating the Gear bezel. The
-
To remove the Web widget from the widget board, the user long-presses the widget and selects its - button. The Tizen framework terminates the widget operations and its instance. The widget and its resources remain on the wearable device, but the user must add the widget to the widget board again to use the widget.
The parent Web application and its other Web widgets (if present) are not affected.
-
To uninstall the parent Web application and all its widgets, the user long-presses the Web application and selects its - button. In this case, the Web application package (including all its widgets and their resources) is deleted from the wearable device. The Tizen framework removes the Web application from the application tray and deletes all its widgets from the widget board.
Package and configuration
The Web widget application must be included in the same package with its parent Web application. The Web widgets are placed in the widget
subdirectory, which is generated automatically by Tizen Studio. The following example shows a typical structure of a Web application package with 2 Web widgets:
.wgt
index.html
config.xml
icon.png
css
images
js
lib
locales
widget
widget001
index.html
config.xml
preview.png
css
images
js
lib
locales
widget002
index.html
config.xml
preview.png
css
images
js
lib
locales
The package contains a general config.xml
file for the entire package, and a separate config.xml
file for each widget:
- The
config.xml
file of the package contains the information from all the widget configuration files, in addition to the details of the parent Web application. The runtime of the Tizen platform uses the generalconfig.xml
file for installing the widget applications. - The
config.xml
file of each widget has that widget’s own information.
The following examples show the config.xml
files in a Web application package:
-
The general
config.xml
file for the Web application package:<?xml version="1.0" encoding="UTF-8"?> <widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets" id="http://yourdomain/DynamicSample"> <!--Information about widget001--> <tizen:app-widget id="Zyj5WRVa13.DynamicSample.widget001" primary="true"> <tizen:widget-label>TEST_1</tizen:widget-label> <tizen:widget-content src="widget/widget001/index.html"> <tizen:widget-size preview="widget/widget001/preview.png">2x2</tizen:widget-size> </tizen:widget-content> </tizen:app-widget> <!--Information about widget002--> <tizen:app-widget id="Zyj5WRVa13.DynamicSample.widget002" primary="false"> <tizen:widget-label>TEST_2</tizen:widget-label> <tizen:widget-content src="widget/widget002/index.html"> <tizen:widget-size preview="widget/widget002/preview.png">2x2</tizen:widget-size> </tizen:widget-content> </tizen:app-widget> <tizen:application id="Zyj5WRVa13.DynamicSample" package="Zyj5WRVa13" required_version="2.3.2"/> <icon src="icon.png"/> <name>DynamicSample</name> </widget>
-
The
config.xml
file for widget001:<tizen:app-widget id="Zyj5WRVa13.DynamicSample.widget001" primary="true"> <tizen:widget-label>TEST_1</tizen:widget-label> <tizen:widget-content src="widget/widget001/index.html"> <tizen:widget-size preview="widget/widget001/preview.png">2x2</tizen:widget-size> </tizen:widget-content> </tizen:app-widget>
-
The
config.xml
file for widget002:<tizen:app-widget id="Zyj5WRVa13.DynamicSample.widget002" primary="false"> <tizen:widget-label>TEST_2</tizen:widget-label> <tizen:widget-content src="widget/widget002/index.html"> <tizen:widget-size preview="widget/widget002/preview.png">2x2<tizen:widget-size> </tizen:widget-content> </tizen:app-widget>
UI design
Although only limited subsets of Tizen Web APIs are supported for Web widgets, they provide a wide range of UI designs sufficient for wearable devices. The following sections show various design examples using the HTML elements and CSS properties supported in Web widgets.
Layout
The following UI layouts with code examples are common use cases in widgets on wearable devices.
Figure: UI layouts
-
Text layout
The text layout is the most fundamental layout. You only need to place the text in proper positions by setting margins and paddings of the content element. You can also use the
text-align
CSS property to align the text to left, right, or center.Figure: Text layout
<head> <style> body { margin: 0px; text-align: center; } #content { margin-top: 10px; padding-left: 33px; padding-right: 33px; font-size: 20px; } </style> </head> <body> <div id="content"> Go grandmaster Lee Sedol regained a sizeable slice of human pride on Sunday night when he won the latest game in his historic match with an artificially intelligent machine built by Google researchers. </div> </body>
-
Paragraph layout
You can design a paragraph layout by grouping its content with
<div>
elements and applying styles for each group.Figure: Paragraph layout
<head> <style> body { text-align: center; } #secondDiv { padding-top: 10px; padding-bottom: 10px; } </style> </head> <body> <div id="parentDiv"> <div id="firstDiv"> <div id="firstChildDiv1">Text1</div> <div id="firstChildDiv2">Text2</div> </div> <div id="secondDiv"> <div id="secondChildDiv1">Text1</div> <div id="secondChildDiv2">Text2</div> </div> <div id="thirdChildDiv">Text1</div> </div> </body>
-
Paragraph with images layout
By adding images to a paragraph
<div>
group, you can implement the paragraph layout with images, whose styles are inherited from a parent<div>
element.Figure: Paragraph with images layout
<style> body { text-align: center; } </style> <body> <div id="parentDiv"> <div> <div id="firstChildDiv1"><img src="images/image1.jpg"/></div> <div id="firstChildDiv2">Text2</div> <div id="firstChildDiv3">Text3</div> </div> <div> <div id="secondChildDiv1"><img src="images/image2.jpg"/></div> <div id="secondChildDiv2">Text2</div> <div id="secondChildDiv3">Text3</div> </div> </div> </body>
-
Large image layout
For this layout, you have to check whether the image must be resized by setting the
width
andheight
CSS properties. The image size must be smaller than the screen size.Figure: Large image layout
<head> <style> body { text-align: center; } #largeImage { width: 150px; height: 150px; } </style> </head> <body> <div> <div id="firstChildDiv1">Text1</div> <div id="firstChildDiv2">Text2</div> </div> <div> <div id="secondChildDiv1"><img id="largeImage" src="images/image1.jpg"/></div> </div> <div> <div id="thirdChildDiv1">Text1</div> <div id="thirdChildDiv2">Text2</div> </div> </body>
-
Vertical split layout
You can implement the vertical split layout using the
display
CSS property with theinline-block
value. Theinline-block
elements are inline elements with additionalwidth
andheight
properties. With aninline-block
element, you can easily achieve a grid-like layout.Figure: Vertical split layout
NoteThe widget engine only supports the
block
,inline
,inline-block
, andnone
values for thedisplay
property:
#more { .display: inline-block; }
<head>
<style>
#leftDiv {
text-align: right;
}
#rightDiv {
text-align: left;
}
.split {
display: inline-block;
width: 45%; height: 100%;
}
.imgArea {
width: 50px; height: 100px;
}
</style>
</head>
<body>
<div id="parentDiv">
<div class="split" id="leftDiv">
<div id="leftChildDiv1"><img class="imgArea" src="images/image1.jpg"/></div>
<div id="leftChildDiv2">Text</div>
</div>
<div class="split" id="rightDiv">
<div id="rightChildDiv1"><img class="imgArea" src="images/image2.jpg"/></div>
<div id="rightChildDiv2">Text</div>
</div>
</div>
</body>
-
Icon layout
In this layout, icons are arranged to the screen shape. For this kind of content layout, you can use static or absolute values for the
position
CSS property. You can select a preferred one, but static is recommended for a responsive Web design.Figure: Icon layout
Absolute positioning:
<head> <style> body { width: 360px; height: 360px; margin: 0; } .box { position: absolute; width: 100px; height: 100px; } #topDiv { left: 130px; /* (360/2)-(100/2) */ } #leftDiv { top: 100px; } #rightDiv { top: 100px; left: 260px; /* 360-100 */ } #bottomDiv { top: 200px; left: 130px; /* (360/2)-(100/2) */ } </style> </head> <body> <div class="box" id="topDiv"> <div id="topChildDiv1"><img src="images/image1.jpg"/></div> <div id="topChildDiv2">Top Text</div> </div> <div class="box" id="leftDiv"> <div id="leftChildDiv1"><img src="images/image2.jpg"/></div> <div id="leftChildDiv2">Left Text</div> </div> <div class="box" id="rightDiv"> <div id="rightChildDiv1"><img src="images/image3.jpg"/></div> <div id="rightChildDiv2">Right Text</div> </div> <div class="box" id="bottomDiv"> <div id="bottomChildDiv1"><img src="images/image4.jpg"/></div> <div id="bottomChildDiv2">Bottom Text</div> </div> </body>
Static positioning:
<head> <style> body { width: 360px; height: 360px; margin: 0; } .box { width: 100px; height: 100px; display: inline-block; } #topDiv, #midDiv, #bottomDiv { text-align: center; } #leftDiv { margin-right: 50px; } #rightDiv { margin-left: 50px; } </style> </head> <body> <div id="topDiv"> <div class="box" id="topInnerDiv"> <div id="topChildDiv1"><img src="images/image1.jpg"/></div> <div id="topChildDiv2">Top Text</div> </div> </div> <div id="midDiv"> <div class="box" id="leftDiv"> <div id="leftChildDiv1"><img src="images/image2.jpg"/></div> <div id="leftChildDiv2">Left Text</div> </div> <div class="box" id="rightDiv"> <div id="rightChildDiv1"><img src="images/image3.jpg"/></div> <div id="rightChildDiv2">Right Text</div> </div> </div> <div id="bottomDiv"> <div class="box" id="bottomInnerDiv"> <div id="bottomChildDiv1"><img src="images/image4.jpg"/></div> <div id="bottomChildDiv2">Bottom Text</div> </div> </div> </body>
Style
You can set the widget content styles, such as font and border, by changing the CSS properties. For example, you can set the font and border properties as follows:
#text {
font-size: 20pt;
font-weight: bold; /* Available values: normal, bold, bolder, lighter, number */
text-align: center;
}
#more {
border-style: solid;
border-left-color: lightgray;
border-top-color: lightgray;
}
The following example shows a calendar widget implementation with styles.
Figure: Calendar widget
<!--HTML-->
<!DOCTYPE html>
<html>
<body>
<div id="viewport">
<div id="day">26</div>
<div id="week">Thursday</div>
<div id="scheduleTitle">Project meeting</div>
<div id="scheduleTime">1:00PM-2:00PM</div>
<div id="scheduleTitle">Conference call</div>
<div id="scheduleTime">3:00PM-3:30PM</div>
<div id="more">+3</div>
</div>
</body>
</html>
<!--CSS-->
#viewport {
font-size: 20pt;
text-align: center;
}
#day {
color: green;
font-size: 30pt;
}
#scheduleTitle {
margin-top: 5%;
height: 13%;
font-weight: bold;
font-size: 30pt;
}
#more {
font-size: 16pt;
width: 50px;
display: inline-block;
border-style: solid;
border-left-color: lightgray;
border-top-color: lightgray;
}
#scheduleTime, #more {
margin-top: 2%;
color: gray;
}
Image
You can manage images in a widget with JavaScript code for updating the content.
The following example shows a news briefing widget implementation with images.
Figure: News briefing widget
<!--HTML-->
<!DOCTYPE html>
<html>
<body>
<div class="category"><img id="imgCategory1" src="images/science.png" width="70px"/></div>
<div id="content1">Counter-Terror Office Funds Tube-Launched...</div>
<div class="category"><img id="imgCategory2" src="images/sports.png" width="70px"/></div>
<div id="content2">Presidential Medal of Freedom for Yogi, Mays</div>
<div class="more">+12</div>
</body>
</html>
<!--CSS-->
body {
position: absolute;
width: 360px; height: 360px;
font-size: 20px;
text-align: center;
}
* {
display: block;
margin: 0px; padding: 0px;
}
.category {
margin-top: 40px;
margin-left: 137.5px;
}
.content {
margin-top: 10px;
padding-left: 33px;
padding-right: 33px;
height: 66px;
font-size: 26px;
}
.more {
margin-top: 28px;
height: 20.2px;
}
/* JavaScript */
function onload() {
/* Load news data here */
/* Content update */
document.getElementById('imgCategory1').src = newsData.firstNewsType + '.png';
document.getElementById('imgCategory2').src = newsData.secondNewsType + '.png';
document.getElementById('content1').textContent = newsData.firstNewsData.substring(0,40) + '...';
document.getElementById('content2').textContent = newsData.secondNewsData.substring(0,40) + '...';
}
Animation
For simple and smooth animation effects, use the requestAnimationFrame()
JavaScript method.
The following example shows a weather widget implementation with an image animation.
Figure: Weather widget
var cntImage = 0;
function step() {
document.getElementById('imgWeather').src = 'images/sun_' + (cntImage++) + '.png';
if (cntImage < 4) {
window.requestAnimationFrame(step);
}
}
function goAni() {
window.requestAnimationFrame(step);
}
Similarly, you can create a text scrolling effect using the requestAnimationFrame()
method. This is useful, for example, when displaying a lengthy music title. (Remember that the marquee element is not supported in Web widgets.)
Figure: Scrolling effect
var scrollLength = 0;
function step() {
document.getElementById('scheduleTitle').style.transform='translateX(' + (scrollLength--) + 'px)'
if (scrollLength > -300) { /* Max length */
window.requestAnimationFrame(step);
}
}
function goAni() {
window.requestAnimationFrame(step);
}
Event handling
The Web widget applications support the following events: onload
, onclick
, and visibilityChange
:
-
onload
This event is generated when the Web widget content is loaded onto the widget board. Use it to implement Web widget initialization procedures. For example, initialize Web widget configurations by reading shared data from the parent Web application.
Figure: onload event
<!--HTML--> <element onload="load">
/* JavaScript */ /* Define the event */ object.onload=load; /* Set the event listener */ object.addEventListener('load', load); /* Define the event handler in the main.js file */ function load() { /* Load water data from shared file */ loadWaterData(); /* Change the current amount of water */ document.getElementById('currentWaterNum').textContent = currentWaterNum; /* Change the color of the water cups */ for (var i = 1; i <= currentWaterNum; ++i) { document.getElementById('watercup' + i)).style.backgroundColor = 'blue'; } }
-
onclick
This event is generated when the user taps on an action button, whose function is specified by an HTML element. The following example code shows how to define the function for the ADD WATER button.
Figure: onclick event
<!--HTML--> <element onclick="click">
/* JavaScript */ /* Define the event */ object.onclick=click; /* Set the event listener */ object.addEventListener('click', click); /* Define the event handler in the main.js file */ /* When the user clicks the button, update the status and change the style */ function click() { /* Increase the water amount */ currentWaterNum++; /* Change the current amount of water */ document.getElementById('currentWaterNum').textContent = currentWaterNum; /* Change the color of the water cup */ document.getElementById('watercup' + currentWaterNum).style.backgroundColor = 'blue'; /* Store water data into a shared file */ storeWaterData(); }
-
visibilityChange
This event is generated when the Web widget content becomes visible or hidden.
Figure: visibilityChange event
/* JavaScript */ /* Set the event listener */ document.addEventListener('visibilitychange', visibilitychange); /* Define the event handler in the main.js file */ function visibilitychange() { if (document.visibilityState === 'hidden') { /* Store shared data */ } else { /* Load stored data and update the page */ } }
Communication between web widgets and other applications
Web widgets can communicate with other applications in various ways. As shown in the following table, the available methods depend on the type of the application the Web widget interacts with.
Table: Web widget communication methods
Communication type | Available method |
---|---|
Web widget <–> Parent application (on a wearable device) | Preference API |
Web widget <–> Host application (on a host device) | SAP (Samsung Accessory Protocol) |
Web widget <–> Web server | XMLHttpRequest |
Communicate with a web application on a wearable device
For data sharing between a Web widget and its parent application on the same device, use the Tizen Preference API. The Preference API allows a Web widget to communicate with its parent Web app (and vice versa) by storing key-value pairs in a hashtable-like data structure. The data stored by the Preference API has a “package” scope, which means that any widgets (or a Web app) in a package can access the data stored by the other widgets (or a Web app) in the same package. In addition, the Preference API does not need additional permissions, so no modifications in the config.xml
file are required.
The following table lists the Preference API methods.
Table: Preference API methods
Method | Description |
---|---|
tizen.preference.setValue("key", "value") |
Stores a key-value pair. |
tizen.preference.getValue("key") |
Retrieves a value for the “key” key. |
tizen.preference.exists("key") |
Returns true if the given key exists. |
tizen.preference.remove("key") |
Removes a key-value pair for the “key” key. |
tizen.preference.setChangeListener("key", listener) |
Registers a change listener for “key”. |
tizen.preference.unsetChangeListener("key") |
Unregisters the change listener for “key”. |
The following example shows how to set a key-value pair in the Widget_main.js
file:
function checkPreference() {
if (!tizen.preference.exists('KEY')) {
tizen.preference.setValue('KEY', 'Widget_HELLOWORLD1');
}
if (tizen.preference.exists('KEY')) {
tizen.preference.remove('KEY');
tizen.preference.setValue('KEY', 'Widget_HELLOWORLD2');
}
/* [Log] value for KEY: Widget_HELLOWORLD2 */
console.log('value for KEY: ' + tizen.preference.getValue('KEY'));
/* Callback function */
var listener = function(data) {
/* [Log] Preference with the key: KEY has a new value: APP_HELLOWORLD */
console.log('Preference with the key: ' + data.key + ' has a new value: ' + data.value);
tizen.preference.unsetChangeListener('KEY');
};
tizen.preference.setChangeListener('KEY', listener);
}
To set the value in the WebApp_main.js
file:
window.onload = function() {
var timer = setInterval(function() {
clearInterval(timer);
try {
tizen.preference.setValue('KEY', 'APP_HELLOWORLD');
tizen.application.getCurrentApplication().exit();
} catch (ignore) {}
}, 2000);
};
Tizen Application API
The Application API allows a widget to launch and access installed applications on the same device. For this, you need to set the following privileges:
<tizen:privilege name="http://tizen.org/privilege/application.info"/>
<tizen:privilege name="http://tizen.org/privilege/application.launch"/>
<tizen:privilege name="http://tizen.org/privilege/appmanager.certificate"/>
<tizen:privilege name="http://tizen.org/privilege/appmanager.kill"/>
In addition, to launch an application, its application ID must be used to identify the application:
/* Launch the application */
tizen.application.launch('ApplicationIDToLaunch', onGetAppsContextSuccess);
NoteIt is not recommended for a Web widget to launch other Web widgets. This feature is deprecated in Tizen 3.0.
Communicate with a host application on a host device
The widget and its parent application can reside on separate devices, as when a Web widget is on a wearable device while the host (parent) application is on a mobile device. In this case, the widget and parent applications can communicate through SAP (Samsung Accessory Protocol) to share data between the widget (the consumer in SAP) and the parent application (the provider in SAP).
The following example shows SAP communication implementation between a Web widget on a Tizen wearable device and its parent application on an Android™ mobile device:
-
Widget on a Tizen wearable device:
<!--Privilege--> <tizen:privilege name="http://developer.samsung.com/privilege/accessoryprotocol"/> <!--HTML--> <body> <button id="button1" onclick="getDataFromHostApp();">GetData</button> <div id="result"></div> </body>
/* JavaScript */ var SAAgent = 0; var SASocket = 0; var CHANNELID = 2000; var providerAppName = 'WeatherProvider'; function onerror(err) { /* Error handling */ } var agentCallback = { onconnect: function(socket) { SASocket = socket; SASocket.setSocketStatusListener(function(reason) { disconnect(); }); SASocket.setDataReceiveListener(onreceive); /* Request the provider to get weather info */ SASocket.sendData(CHANNELID, 'request'); }, onerror: onerror }; var peerAgentFindCallback = { onpeeragentfound: function(peerAgent) { try { if (peerAgent.appName == providerAppName) { SAAgent.setServiceConnectionListener(agentCallback); SAAgent.requestServiceConnection(peerAgent); } } catch (err) { /* Error handling */ } }, onerror: onerror }; function onsuccess(agents) { try { if (agents.length > 0) { SAAgent = agents[0]; SAAgent.setPeerAgentFindListener(peerAgentFindCallback); SAAgent.findPeerAgents(); } } catch (err) { /* Error handling */ } } function onreceive(channelId, data) { document.getElementById('result').textContent = data; } function getDataFromHostApp() { if (SASocket) { return false; /* Already connected */ } try { webapis.sa.requestSAAgent(onsuccess, function(err) { /* Error handling */ }); } catch (err) { /* Error handling */ } }
-
Parent application on an Android mobile device:
For the provider application on the host device, you need to:
- Declare the permissions, service, broadcast receiver, and intent-filter in the Android manifest file.
- Add the Accessory Service Profile in the
config.xml
andAndroidManifest.xml
files in order to allow the applications to communicate with each other.
<!--Permissions--> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="com.samsung.accessory.permission.ACCESSORY_FRAMEWORK"/> <uses-permission android:name="com.samsung.wmanager.APP"/> <uses-permission android:name="com.samsung.wmanager.ENABLE_NOTIFICATION"/> <!--Service registration--> <service android:name=".WeatherProviderForWidget"/> <!--Broadcast receiver and intent-filter--> <receiver android:name="com.samsung.android.sdk.accessory.ServiceConnectionIndicationBroadcastReceiver"> <intent-filter> <action android:name="android.accessory.service.action.ACCESSORY_SERVICE_CONNECTION_IND"/> </intent-filter> </receiver> <receiver android:name="com.samsung.android.sdk.accessory.RegisterUponInstallReceiver"> <intent-filter> <action android:name="android.accessory.device.action.REGISTER_AFTER_INSTALL"/> </intent-filter> </receiver> <!--Service profile information--> <meta-data android:name="AccessoryServicesLocation" android:value="/res/xml/accessoryservices.xml"/>
// Activity (Main) code try { // To widget WeatherProviderForWidget.mConnectionHandler.send(WeatherProviderForWidget.WIDGET_CHANNEL_ID, jsonData.toString().getBytes()); } catch (JSONException e) { e.printStackTrace(); } catch (IOException e_io) { e_io.printStackTrace(); } // Service (WeatherProviderForWidget) @Override protected void onServiceConnectionResponse(SAPeerAgent peerAgent, SASocket socket, int result) { if (result == SAAgent.CONNECTION_SUCCESS) { if (socket != null) { mConnectionHandler = (ServiceConnection) socket; } } else if (result == SAAgent.CONNECTION_ALREADY_EXIST) { Log.e(TAG, "onServiceConnectionResponse, CONNECTION_ALREADY_EXIST"); } } public class WeatherProviderForWidget extends SAAgent { private static final String TAG = "WeatherProviderForWidget"; private static final Class<ServiceConnection> SASOCKET_CLASS = ServiceConnection.class; static ServiceConnection mConnectionHandler = null; static final int WIDGET_CHANNEL_ID = 1000; @Override public void onCreate() { super.onCreate(); SA mAccessory = new SA(); try { mAccessory.initialize(this); // Connect to Widget } catch (Exception e1) { e1.printStackTrace(); } } @Override protected void onServiceConnectionRequested(SAPeerAgent peerAgent) { if (peerAgent != null) { acceptServiceConnectionRequest(peerAgent); // Connection Accepted } } public class ServiceConnection extends SASocket { public ServiceConnection() { super(ServiceConnection.class.getName()); } @Override public void onReceive(int channelId, byte[] data) { if (mConnectionHandler == null) { return; } String req_message = new String(data); // Get data from Widget if (req_message.equals(new String("request"))) { final JSONObject jsonData = new JSONObject(); try { Calendar calendar = new GregorianCalendar(); SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm"); String timeStr = dateFormat.format(calendar.getTime()); jsonData.put("time_text", timeStr); jsonData.put("city_text", "city name"); mConnectionHandler.send(WIDGET_CHANNEL_ID, jsonData.toString().getBytes()); } catch (JSONException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } else if (req_message.equals(new String("delete_widget"))) { Log.e(TAG, "The widget was deleted from the viewer"); } else if (req_message.equals(new String("Add city"))) { Context context = getApplicationContext(); Intent intent = new Intent(context, ProviderActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } } @Override protected void onServiceConnectionLost(int reason) { Log.e(TAG, "Service Connection is Lost"); mConnectionHandler = null; } } }
Communicate with a web server
To get data from a Web server through the Internet, use the XMLHttpRequest API. The Web widget engine, however, does not support the full XMLHttpRequest specification. It only supports the GET
and POST
methods, and the TEXT
and JSON
data types. This design decision emphasizes the read-only behavior of the Web widgets and meets the runtime memory requirements. Use Web widgets to display information in a compact manner, and do not create new resources using the PUT
method: as user interaction is not intended and can exceed the widget’s maximum allowed memory, it can lead to security risks.
The following example shows Web widget communication with a Web server:
<!--Privilege-->
<tizen:privilege name="http://tizen.org/privilege/internet"/>
<!--HTML-->
<body>
<button id="button1" onclick="getDataFromNetwork('txt.txt', handleResponseTEXT);">Text</button>
<button id="button2" onclick="getDataFromNetwork('json.json', handleResponseJSON);">Json</button>
<div id="result"></div>
</body>
/* JavaScript */
function errorHandling(e) {
if (e.target.readyState == 3) {
/* Error handling */
e.target.abort();
}
}
function getDataFromNetwork(file, handler) {
var xhr = new XMLHttpRequest();
xhr.open('GET', file, true);
xhr.onreadystatechange = handler;
xhr.onload = function() {
if (this.status == 200) {
/* Handle the response */
}
};
xhr.send();
}
/* If getting Text data */
function handleResponseTEXT(e) {
if (e.target.readyState == 4) {
if (e.target.status == 200) {
document.getElementById('result').textContent = e.target.responseText;
} else {
/* Error handling */
}
}
}
/* If getting JSON data */
function handleResponseJSON(e) {
if (e.target.readyState == 4) {
if (e.target.status == 200) {
var data = JSON.parse(e.target.responseText);
var val = data.employees;
var result = val[0].firstName + ' ' + val[0].lastName;
document.getElementById('result').textContent = result;
} else {
/* Error handling */
}
}
}
Locale information formatting
You can use a Date
object to format locale information in a widget.
The following example provides the date information in different formats:
var d = new Date();
d.toLocaleString(); /* '2/1/2013 7:37:08 AM' */
d.toLocaleDateString(); /* '2/1/2013' */
d.toLocaleTimeString(); /* '7:38:05 AM' */
Debug
You can debug and validate your Web widget. Currently, there are 2 approaches to debugging a Web widget:
- Console log
- Web debugger
The validation process checks whether a Web widget is compliant with the specifications and whether it contains unsupported HTML elements and CSS properties.
Debug with the console log
Using the console.log()
method is a simple and convenient way of debugging a Web widget. The following figure shows how to debug a Web widget using Tizen Studio.
Figure: Debugging with the console log
In addition, you can use the following command to print the console.log()
message in the terminal:
sdb dlog | grep StarFish
The following figure shows the sbd dlog
command in action.
Figure: Debugging messages in the terminal
Debug with the web debugger
To make Web widgets lighter, debugging features may not be supported by default. In this case, take the following steps to use a built-in Web application debugger:
- Create an empty Web application template.
- Copy the Web widget-related files (create a Web application with the same content as in the Web widget).
- Run the built-in Web debugger.
The following figure shows how to run the built-in Web debugger.
Figure: Web debugger
In addition, you can still use the console.log()
method as shown in the following figure.
Figure: The console.log()
method
Similarly, you can also use the following command to print the console.log()
messages in a terminal:
sdb dlog | grep ConsoleMessage
The following figure shows the sdb dlog
command in action.
Figure: Debugging messages in the terminal
Validate a web widget
You can validate a Web widget using the following validators:
- HTML validator
- CSS validator
- JS validator
You can enable or disable these validators in the application preferences. Go to Windows > Preferences > Tizen Studio > Web > WebWidget, and check the applicable boxes.
Figure: Web widget validation
The validation is performed automatically when the project or the package is built, or when the application is run.
When the validation is complete, its results are shown in the Problems view. If the view is not displayed, go to Window > Show view > Problems, or use the keyboard shortcut Shift + Alt + Q + X.
Figure: Web widget validation result
Performance considerations
It is important to prevent unnecessary performance degradation in widgets. As a result, some restrictions must be followed when implementing Web widgets:
-
External network resources
Linking external network resources in an HTML document often introduces significant network delays that result in slow loading of Web applications. Therefore, it is not allowed to load resources from external networks in a Web widget application.
The following example illustrates forbidden external network resources:
<!--HTML--> <img id="img_water" src="http://spec.example.com/image.png"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"/>
-
Image size
The width and the height of the image files in Web widgets are limited to 1.5 times the base image resolution. For the wearable profile, for example, the base image resolution is 360 x 360, so the maximum size of the images is 540 x 540. As long as the image size is within the limit, you can include multiple images in the widget.
Figure: Width and height of the image
-
Resource size
A Web widget application consists of HTML documents, and JavaScript, CSS, and other resource files. To improve the loading performance, the total size of the Web widget application cannot exceed 50 Kbytes. Because of this limitation, you cannot include heavy JavaScript and CSS libraries, such as jQuery and AngularJS:
<!--HTML--> <script src="lib/tau/wearable/js/tau.js"/>
FAQ
- How are click and touch events handled in Web widgets?
- Can I apply heading styles to text?
- Can I use hyperlinks in Web widgets?
- Which font styles are supported?
- What is the best way to use the
<img>
element? - Why can’t I use iframes?
- Which media elements are supported?
- How can I create tables?
- What kind of forms can I use?
- How can I mimic select elements instead of using the
querySelector()
method? - How can I retrieve nodes without the
NodeIterator
object? - Is
innerHTML
orinnerText
supported? - How can logging be performed in the emulator?
- Why does the
responseXML
property returnundefined
? - How can I use the
response
andresponseType
attributes? - How can I change the Web widget text font?
- Can I set a border style, such as
border-radius
? - Can I animate images without a 2D canvas?
- Is the Web Widget Specification a new Web standard?
- Which elements or properties can I use?
- How can I design my Web widget layout for a circular shape?
- Can I use external JavaScript and CSS libraries?
- What kind of events can I use for user interaction?
- How can I access the Internet from a Web widget, and what restrictions are there?
- Is it possible to implement Web widgets without a Web application?
- How can I determine which APIs are supported in Web widgets?
- Can Web widgets reuse the JavaScript library or CSS styles of their parent Web application?
- What are the benefits of Web widgets compared with native widget applications?
- What type of content is best for Web widgets?
- Can I use CSS
ellipsis
? - Do my customers download the Web widgets when downloading a Web application?
- Is the widget creation initiated by the widget adding and resuming actions?
- When a Web widget is removed, which events are fired?
- What are the Web widget file size limitations (HTML, CSS, JavaScript)?
How are click and touch events handled in Web widgets?
The Web widget engine supports only the onclick
event handler for click and touch events. Implement and bind an event handler to the target element. For more information, see onclick Event.
Can I apply heading styles to text?
The Web widget engine does not support HTML heading styles (h1
, h2
, …, h6
). The heading styles are typically used to structure Web pages displayed in browsers. To make a heading text, apply a suitable CSS font-style
property.
Can I use hyperlinks in Web widgets?
The Web widget engine does not support hyperlinks. To change from the current Web widget page, use a CSS transition or implement your service as a Web application.
Which font styles are supported?
The Web widget engine supports the <br>
and <span>
elements for text-level semantics (for more information, see HTML). You can also use CSS properties to make the text display like text with text-level semantics elements applied. The following table lists examples of typical element/CSS property correlations.
Table: Element and CSS property correlations
Unsupported element | Similar supported CSS property and values |
---|---|
<strong> |
font-weight: bold |
<small> |
font-size: smaller |
<s> |
text-decoration: line-through |
<sub> |
vertical-align: sub and font-size: smaller |
<sup> |
vertical-align: super and font-size: smaller |
<i> |
font-style: italic |
<b> |
font-weight: bold |
<u> |
text-decoration: underline |
What is the best way to use the <img>
element?
To increase performance and reduce the memory footprint, the Web widget engine imposes 2 limitations on the <img>
element:
- Supported image file formats: PNG, JPG, GIF
- Supported resolutions: lower than 1.5 times the base image resolution
Why can’t I use iframes?
Typically, iframes are used for embedding another document within the current document. However, Web widgets provide simple services and content. Therefore, the Web widget engine does not support iframes.
Which media elements are supported?
The Web widget engine supports the <img>
element only, and does not support <audio>
and <video>
elements.
How can I create tables?
The Web widget engine does not support the <table>
HTML element. To create a table-like layout, use the <div>
and <border>
elements, as shown in the following example:
<!--CSS style-->
<style>
body {
position: absolute;
margin: 0px;
padding: 0px;
top: 0px;
left: 0px;
width: 360px;
height: 360px;
font-size: 1.125rem;
color: Black;
background-color: White;
}
#leftDiv {
text-align: center;
border: 1px solid red;
}
#rightDiv {
text-align: center;
border: 1px solid red;
margin-left: -5px;
}
.split {
display: inline-block;
width: 45%; height: 100%;
}
</style>
<!--Table-like div-->
<div id="parentDiv">
<div class="split" id="leftDiv">
First Name
</div>
<div class="split" id="rightDiv">
Last Name
</div>
</div>
<div id="parentDiv">
<div class="split" id="leftDiv">
Eve
</div>
<div class="split" id="rightDiv">
Jackson
</div>
<div class="split" id="leftDiv">
John
</div>
<div class="split" id="rightDiv">
Doe
</div>
<div class="split" id="leftDiv">
Adam
</div>
<div class="split" id="rightDiv">
Johnson
</div>
</div>
What kind of forms can I use?
The Web widget engine does not support the <form>
element. However, you can create form-like elements using the <div>
element and CSS styles.
How can I mimic select elements instead of using the querySelector()
method?
The Web widget engine does not support the querySelector()
method. However, you can create an alternative select element, as shown in the following example:
var parent = document.getElementById('parentDiv');
var c = parent.children;
var i;
for (i = 0; i < c.length; i++) {
if (c[i].id === 'leftDiv') {
/* Do something */
}
}
How can I retrieve nodes without the NodeIterator
object?
The Web widget engine does not support the NodeIterator
object. Retrieve the children
attribute of a node as shown in the following example:
var c = document.body.children;
var i;
for (i = 0; i < c.length; i++) {
c[i].style.backgroundColor = 'red';
}
Is innerHTML
or innerText
supported?
The Web widget engine does not support innerHTML
and innerText
properties. To get the text data of an element, use the textContent
attribute, as shown in the following example:
var parent = document.getElementById('parentDiv');
var parentText = parent.textContent;
How can logging be performed in the emulator?
Use the console.log()
method in the JavaScript code. You can see the logs in Tizen Studio.
Why does the responseXML
property return undefined
?
The XMLHttpRequest()
method is supported only for the text data type. Therefore, the responseXML
property is not necessary.
How can I use the response
and responseType
attributes?
You cannot use them, because the XMLHttpRequest()
method is supported for the text data type only. For more information, see XMLHttpRequest.
How can I change the Web widget text font?
For performance reasons, the Web widget engine does not support the font-family
CSS property. However, you can use combinations of font-size
, font-weight
, and font-style
properties to change your Web widget font.
Can I set a border style, such as border-radius
?
Not yet. This feature is going to be supported in the next release of the Web widget engine.
Can I animate images without a 2D canvas?
The Web Widget Specification supports the requestAnimationFrame()
method and CSS transform for implementing animations. For an example code, see Animation.
Is the Web Widget Specification a new Web standard?
No, the Web Widget Specification is a limited set of the W3C standard specification. The Web widget APIs are a subset of the Tizen Device APIs.
Which elements or properties can I use?
For the supported elements and properties, see Tizen Wearable Web Widget Specification.
How can I design my Web widget layout for a circular shape?
There are no specific functions for a circular shape. For circular layout samples, see Layout.
Can I use external JavaScript and CSS libraries?
According to the Web Widget Specification, the content size of each Web widget is limited to 50 kB. For Web widget content that is less than or equal to 50 kB, JavaScript or CSS files can be included. However, for performance reasons, the files cannot be imported from an external network. For more information, see the external network resource section in Performance Considerations.
What kind of events can I use for user interaction?
Due to UX restrictions, Web widgets only allow the use of the onclick
events for user interaction.
How can I access the Internet from a Web widget, and what restrictions are there?
Accessing Internet is available through the XMLHttpRequest()
method. For an example code, see Communicating with a Web Server.
Is it possible to implement Web widgets without a Web application?
For your convenience during testing and debugging only, the Web widget engine supports the “Only Web Widget Mode”. To distribute Web widgets through the store, each Web widget must have at least 1 parent Web application in the package. For more information, see Application Model.
How can I determine which APIs are supported in Web widgets?
For the APIs supported by the Web Widget Specification, see Tizen Wearable Web Widget Specification. Additionally, Tizen Studio provides a Web widget validator that indicates whether a typed-in API follows the Web Widget Specification.
Can Web widgets reuse the JavaScript library or CSS styles of their parent Web application?
Because Web application and Web widget resources are isolated from each other, Web widgets cannot use the JavaScript or CSS files in their parent Web application. The virtual root paths of the Web application and its Web widgets are not the same. You can copy Web application JavaScript and CSS files to the Web widget’s folder. However, the Web Widget Specification places more restrictions on the Web widget files than on the Web application files. Therefore, verify all copied Web application JavaScript and CSS files using the Web widget validator.
What are the benefits of Web widgets compared with native widget applications?
Because Web widgets are implemented through the Web Widget Specification, Web-friendly developers can create Web widgets more easily and quickly than native widget applications.
What type of content is best for Web widgets?
Typically as part of a Web application, Web widgets provide their users with important Web application functions (such as launching the parent Web application), and brief, important Web application information. Therefore, simple and lightweight services are best suited for Web widgets.
Can I use CSS ellipsis
?
Currently, CSS ellipsis
is not supported. However, the string length can be limiting by using JavaScript. For an example code, see the Scrolling Text sample in Animation.
Do my customers download the Web widgets when downloading a Web application?
Yes, the Web widgets must be packaged together with their parent Web application. The entire package is distributed to customers through the store.
Is the widget creation initiated by the widget adding and resuming actions?
After the widget creation is initiated by the widget adding action, a resume action is not triggered. The resume action is triggered only when a Web widget is shown after being hidden (by rotating the Gear device bezel). For the Web widget life-cycle details, see Life-cycle.
When a Web widget is removed, which events are fired?
After removal, no corresponding event is fired because no event is considered necessary for termination.
What are the Web widget file size limitations (HTML, CSS, JavaScript)?
For the Web widget file and image size limits, see Performance Considerations.
Related information
- Dependencies
- Tizen 2.3.2 for Wearable