--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=9" />
+ <link rel="stylesheet" type="text/css" href="../css/styles.css" />
+ <link rel="stylesheet" type="text/css" href="../css/snippet.css" />
+ <script type="text/javascript" src="../scripts/snippet.js"></script>
+ <script type="text/javascript" src="../scripts/jquery.util.js" charset="utf-8"></script>
+ <script type="text/javascript" src="../scripts/common.js" charset="utf-8"></script>
+ <script type="text/javascript" src="../scripts/core.js" charset="utf-8"></script>
+ <script type="text/javascript" src="../scripts/search.js" charset="utf-8"></script>
+
+ <title>The Ambient Weather Sample Overview</title>
+</head>
+
+<body class="no-toc" onload="prettyPrint()" style="overflow: auto;">
+
+<div id="toc-navigation">
+</div>
+
+<div id="container"><div id="contents"><div class="content">
+ <div id="profile">
+ <p><img alt="Wearable native" src="../images/wearable_s_n.png"/></p>
+ </div>
+
+ <h1>Ambient Weather Sample Overview</h1>
+
+<p>The Ambient Weather sample application demonstrates how to implement a simple watch with current weather display in ambient mode.</p>
+
+<p>The following figure illustrates two screens of the (Circle) Ambient Weather sample application: the normal mode digital watch view and the ambient mode view with weather data.</p>
+
+<p class="figure">Figure 1: Ambient Weather views</p>
+ <p align="center">
+ <img alt="Ambient Weather views" src="../images/ambientweather_wn0.png" height="240" width="240"/>
+ <img alt="Ambient Weather views" src="../images/ambientweather_wn1.png" height="240" width="240"/>
+ </p>
+
+<p class="figure">Figure 2: Ambient Weather widgets structure</p>
+<p align="center">
+ <img alt="(Circle) Sensors widgets structure" src="../images/ambientweather_wn3.png" height="274" width="284"/>
+</p>
+
+<p>It is worth mentioning that this application is multithreaded. The time consuming task of requesting the weather data has been moved to a separate thread to avoid UI lockups.
+It is demonstarted in Fig. 3.</p>
+
+<p class="figure">Figure 3: Weather data request diagram</p>
+<p align="center">
+ <img alt="(Circle) Sensors widgets structure" src="../images/ambientweather_wn2.png" height="438" width="839"/>
+</p>
+
+<h2>Prerequisites</h2>
+<p>To ensure proper application execution, the following privileges must be set:
+<ul>
+<li><span style="font-family: Courier New,Courier,monospace">http://tizen.org/privilege/network.get</span></li>
+<li><span style="font-family: Courier New,Courier,monospace">http://tizen.org/privilege/keymanager</span></li>
+<li><span style="font-family: Courier New,Courier,monospace">http://tizen.org/privilege/internet</span></li>
+<li><span style="font-family: Courier New,Courier,monospace">http://tizen.org/privilege/alarm.set</span></li>
+</ul>
+</p>
+
+<h2>Implementation</h2>
+
+<h3>Main module</h3>
+<p>The <span style="font-family: Courier New,Courier,monospace">main()</span> function of the sample application is show below. The application loop
+is started when the <span style="font-family: Courier New,Courier,monospace">watch_app_main()</span>
+function is invoked. An object of <span style="font-family: Courier New,Courier,monospace">watch_app_lifecycle_callback_s</span> type can be passed to it.
+Notice how it differs from <span style="font-family: Courier New,Courier,monospace">ui_app_lifecycle_callback_s</span> type used in the standard application type.
+The <span style="font-family: Courier New,Courier,monospace">watch_app_lifecycle_callback_s</span> structure introduces three new pointers to the following callback functions:
+</p>
+<ul>
+ <li><span style="font-family: Courier New,Courier,monospace">watch_app_time_tick_cb</span> - called every second when the application is in normal mode, giving the application a chance to refresh the time indicator,</li>
+ <li><span style="font-family: Courier New,Courier,monospace">watch_app_ambient_tick_cb</span> - called every minute when the application is in ambient mode, giving the application a chance to refresh the time indicator,</li>
+ <li><span style="font-family: Courier New,Courier,monospace">watch_app_ambient_changed_cb</span> - called whenever the application enters normal or ambient mode.</li>
+</ul>
+
+<pre class="prettyprint">
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+
+ watch_app_lifecycle_callback_s event_callback = {0,};
+
+ event_callback.create = app_create;
+ event_callback.resume = app_resume;
+ event_callback.pause = app_pause;
+ event_callback.terminate = app_terminate;
+ event_callback.time_tick = app_time_tick;
+ event_callback.ambient_tick = app_time_tick;
+ event_callback.ambient_changed = app_ambient_changed;
+
+ ret = watch_app_main(argc, argv, &event_callback, NULL);
+ // Error handling ...
+
+ return ret;
+}
+</pre>
+
+<pre class="prettyprint">
+static void app_time_tick(watch_time_h watch_time, void *data)
+{
+ // Variables definitions and error handling ...
+ __get_date_from_watch_time(watch_time,
+ &year, &month, &day, &day_of_week,
+ &hours, &minutes, &seconds);
+
+ controller_tick(hours, minutes, seconds, year, month, day, day_of_week);
+}
+</pre>
+
+<pre class="prettyprint">
+static void app_ambient_changed(bool ambient_mode, void *data)
+{
+ controller_set_ambient_mode(ambient_mode);
+}
+</pre>
+
+<pre class="prettyprint">
+static void __get_date_from_watch_time(const watch_time_h watch_time,
+ int *year, int *month, int *day, int *day_of_week,
+ int *hours, int *minutes, int *seconds)
+{
+ watch_time_get_hour24(watch_time, hours);
+ watch_time_get_minute(watch_time, minutes);
+ watch_time_get_second(watch_time, seconds);
+ watch_time_get_year(watch_time, year);
+ watch_time_get_month(watch_time, month);
+ watch_time_get_day(watch_time, day);
+ watch_time_get_day_of_week(watch_time, day_of_week);
+}
+</pre>
+
+<h3>Main controller module</h3>
+<p>Four important functions of this module are presented below. The <span style="font-family: Courier New,Courier,monospace">controller_start_application()</span>
+function is called at the application's startup. It sets up the view and initiates the
+<span style="font-family: Courier New,Courier,monospace">weather_poll_thread</span>
+module by passing the <span style="font-family: Courier New,Courier,monospace">__weather_poll_data_ready_cb()</span> callback function to it. It also sets the current time on the watch view.</p>
+
+<pre class="prettyprint">
+bool controller_start_application(int width, int height,
+ int hour, int min, int sec,
+ int year, int month, int day, int week_day)
+{
+ if (!view_create_gui(width, height))
+ return false;
+
+ if (!weather_poll_thread_init(__weather_poll_data_ready_cb))
+ return false;
+
+ view_set_time(hour, min, sec, year, month, day, week_day);
+
+ return true;
+}
+</pre>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">controller_set_ambient_mode()</span> function is called from
+<span style="font-family: Courier New,Courier,monospace">app_ambient_changed()</span>
+callback, defined in the main module. This way, the application can track whether it is in ambient or normal mode.
+It is recommended to stop any power consuming operations in the ambient mode. For example, you can change the display state to one that has most of its pixels dark.</p>
+
+<pre class="prettyprint">
+void controller_set_ambient_mode(bool ambient_mode)
+{
+ cdata.ambient_mode = ambient_mode;
+ view_set_ambient(cdata.ambient_mode);
+ if (cdata.ambient_mode) {
+ wifi_monitor_stop_measure();
+ } else {
+ wifi_monitor_start_measure(__wifi_rssi_level_changed_cb);
+ }
+}
+</pre>
+<p>The <span style="font-family: Courier New,Courier,monospace">controller_tick()</span>
+is called with one second interval when the application is in normal mode
+and with one minute interval when it is in ambient mode. It updates the time view display.</p>
+
+<pre class="prettyprint">
+void controller_tick(int hour, int min, int sec,
+ int year, int month, int day, int week_day)
+{
+ view_set_time(hour, min, sec, year, month, day, week_day);
+}
+</pre>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">__weather_poll_data_ready_cb()</span>
+callback is called in the main thread context whenever the weather polling thread ends its work successfully.
+This function updates the UI in ambient mode by displaying the data received from the server.</p>
+
+<pre class="prettyprint">
+static void __weather_poll_data_ready_cb(xml_weather_t *weather, const void *icon_data, int icon_data_len)
+{
+ if (weather) {
+ view_set_temperature(weather->temperature.value, weather->temperature.unit);
+ view_set_city(weather->city.name, weather->city.country);
+ view_set_humidity(weather->humidity.value, weather->humidity.unit);
+ view_set_pressure(weather->pressure.value, weather->pressure.unit);
+ view_set_wind(weather->wind.name, weather->wind.speed_value, weather->wind.direction_name);
+ view_set_clouds(weather->clouds.name);
+ view_set_percipitation(weather->precipitation.value);
+ view_set_last_update(asctime(&weather->last_update));
+ }
+
+ if (icon_data && icon_data_len > 0) {
+ view_set_icon(icon_data, icon_data_len);
+ }
+}
+</pre>
+
+<h3>Weather poll thread controller module</h3>
+
+<p>This module introduces a single <span style="font-family: Courier New,Courier,monospace">ecore timer</span> and its callback launched periodically to execute server data poll function in a separate thread.
+Initialization code is shown below.</p>
+
+<pre class="prettyprint">
+bool weather_poll_thread_init(weather_poll_data_ready_cb cb)
+{
+ // Variables definitions and error handling ...
+
+ wpt.tim = ecore_timer_add(1.0, __weather_poll_timer_cb, NULL);
+
+ // Error handling ...
+
+ ecore_timer_freeze(wpt.tim);
+
+ return true;
+}
+</pre>
+
+<pre class="prettyprint">
+static Eina_Bool __weather_poll_timer_cb(void *data)
+{
+ ecore_timer_interval_set(wpt.tim, WEATHER_POLL_INTERVAL_SEC);
+
+ if (!wpt.thread_h) {
+ wpt.thread_h = ecore_thread_run(__thread_function, __thread_end_cb, __thread_cancelled_cb, NULL);
+
+ // Error handling ...
+ }
+
+ return EINA_TRUE;
+}
+</pre>
+
+<p>Both <span style="font-family: Courier New,Courier,monospace">__thread_function()</span>
+and <span style="font-family: Courier New,Courier,monospace">__weather_data_read_cb()</span> functions are executed
+on behalf of a separate thread. Since <span style="font-family: Courier New,Courier,monospace">weather_query()</span>
+is a blocking function, its execution from main thread would lock up the UI.
+</p>
+<pre class="prettyprint">
+static void __thread_function(void *data, Ecore_Thread *thread)
+{
+ if (!weather_query(__weather_data_read_cb))
+ dlog_print(DLOG_ERROR, LOG_TAG, "Failed to make a query");
+}
+</pre>
+
+<p>Any UI update function calls from <span style="font-family: Courier New,Courier,monospace">__weather_data_read_cb()</span>
+are prohibited. So this callback only stores pointers to received data in common memory area.</p>
+
+<pre class="prettyprint">
+static void __weather_data_read_cb(xml_weather_t *weather, image_buffer_t *image_buffer)
+{
+ wpt.weather = weather;
+ wpt.image_buffer = image_buffer;
+}
+</pre>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">__thread_end_cb()</span> however is called automatically when the
+<span style="font-family: Courier New,Courier,monospace">__thread_function()</span> finishes successfully.
+It is called on behalf of the main thread and this is why it can call a callback from the main controller (updating the UI).
+Server data pointers, previously stored by the <span style="font-family: Courier New,Courier,monospace">__weather_data_read_cb()</span>
+function, are used.
+</p>
+
+<pre class="prettyprint">
+static void __thread_end_cb(void *data, Ecore_Thread *thread)
+{
+ char *buffer = NULL;
+ int buffer_size = 0;
+
+ if (wpt.image_buffer) {
+ buffer = wpt.image_buffer->buffer;
+ buffer_size = wpt.image_buffer->size;
+ }
+
+ if (wpt.cb)
+ wpt.cb(wpt.weather, buffer, buffer_size);
+
+ xml_weather_dispose(wpt.weather);
+ weather_free_image_buffer(wpt.image_buffer);
+ wpt.weather = NULL;
+ wpt.image_buffer = NULL;
+ wpt.thread_h = NULL;
+}
+</pre>
+
+<h3>Main view module</h3>
+
+<p>The <span style="font-family: Courier New,Courier,monospace">watch_app_get_elm_win()</span>
+function is used to obtain a special watch type window. This way the application can receive ambient/normal mode switch events properly.</p>
+
+<pre class="prettyprint">
+bool view_create_gui(int width, int height)
+{
+ watch_app_get_elm_win(&vd.win);
+
+ // Error handling ...
+
+ evas_object_resize(vd.win, width, height);
+
+ vd.digital_clock = digital_clock_create(vd.win, width, height);
+ evas_object_show(vd.digital_clock);
+
+ vd.weather = weather_create(vd.win, width, height);
+
+ // Common code ...
+}
+</pre>
+
+<p>Each time a time tick occurs, the controller module calls <span style="font-family: Courier New,Courier,monospace">view_set_time()</span>
+function. It updates the digital clock available in the normal application mode.</p>
+
+<pre class="prettyprint">
+void view_set_time(int hours, int minutes, int seconds,
+ int year, int month, int day, int week_day)
+{
+ digital_clock_set_time(vd.digital_clock, hours, minutes);
+}
+</pre>
+
+<p>The function below is called each time the application mode change occurs. Notice that in ambient mode only the
+weather view is shown, whereas in normal mode only the digital clock is visible.</p>
+
+<pre class="prettyprint">
+void view_set_ambient(bool on_off)
+{
+ vd.ambient = on_off;
+
+ if (on_off) {
+ evas_object_show(vd.weather);
+ evas_object_hide(vd.digital_clock);
+ } else {
+ evas_object_show(vd.digital_clock);
+ evas_object_hide(vd.weather);
+ }
+}
+</pre>
+
+<script type="text/javascript" src="../scripts/jquery.zclip.min.js"></script>
+<script type="text/javascript" src="../scripts/showhide.js"></script>
+</div></div></div>
+
+<a class="top sms" href="#"><img src="../images/btn_top.gif" alt="Go to top" /></a>
+
+<div id="footer">
+<p class="footer">Except as noted, this content - excluding the Code Examples - is licensed under <a href="http://creativecommons.org/licenses/by/3.0/legalcode" target="_blank">Creative Commons Attribution 3.0</a> and all of the Code Examples contained herein are licensed under <a href="https://www.tizen.org/bsd-3-clause-license" target="_blank">BSD-3-Clause</a>.<br/>For details, see the <a href="https://www.tizen.org/content-license" target="_blank">Content License</a>.</p>
+</div>
+
+<script type="text/javascript">
+var _gaq = _gaq || [];
+_gaq.push(['_setAccount', 'UA-25976949-1']);
+_gaq.push(['_trackPageview']);
+(function() {
+var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+})();
+</script>
+
+</body>
+</html>