application sources from tizen_2.2 72/10472/1 tizen
authorPiotr Dabrowski <p.dabrowski2@samsung.com>
Wed, 2 Oct 2013 08:19:31 +0000 (10:19 +0200)
committerPiotr Dabrowski <p.dabrowski2@samsung.com>
Wed, 2 Oct 2013 08:19:31 +0000 (10:19 +0200)
Change-Id: Iefce6159f80ca8d9dae4852c2884af5c8a4da1da

34 files changed:
bluetoothchat-snapshot.png [new file with mode: 0644]
description.xml [new file with mode: 0755]
description.xsl [new file with mode: 0755]
project/.project [new file with mode: 0644]
project/AUTHORS [new file with mode: 0644]
project/LICENSE.Flora [new file with mode: 0644]
project/NOTICE [new file with mode: 0644]
project/config.xml [new file with mode: 0644]
project/css/style.css [new file with mode: 0644]
project/icon.png [new file with mode: 0644]
project/index.html [new file with mode: 0644]
project/js/app.client.js [new file with mode: 0644]
project/js/app.client.model.js [new file with mode: 0644]
project/js/app.config.js [new file with mode: 0644]
project/js/app.helpers.js [new file with mode: 0644]
project/js/app.js [new file with mode: 0644]
project/js/app.model.js [new file with mode: 0644]
project/js/app.server.js [new file with mode: 0644]
project/js/app.server.model.js [new file with mode: 0644]
project/js/app.ui.events.js [new file with mode: 0644]
project/js/app.ui.js [new file with mode: 0644]
project/js/app.ui.templateManager.js [new file with mode: 0644]
project/js/main.js [new file with mode: 0644]
project/templates/bye_popup.tpl [new file with mode: 0644]
project/templates/chat_page.tpl [new file with mode: 0644]
project/templates/choose_page.tpl [new file with mode: 0644]
project/templates/keyboard_page.tpl [new file with mode: 0644]
project/templates/left_bubble.tpl [new file with mode: 0644]
project/templates/message_popup.tpl [new file with mode: 0644]
project/templates/right_bubble.tpl [new file with mode: 0644]
project/templates/server_row.tpl [new file with mode: 0644]
tizen-app-template.xml [new file with mode: 0755]
tizen_32.png [new file with mode: 0644]
tizen_64.png [new file with mode: 0644]

diff --git a/bluetoothchat-snapshot.png b/bluetoothchat-snapshot.png
new file mode 100644 (file)
index 0000000..e972127
Binary files /dev/null and b/bluetoothchat-snapshot.png differ
diff --git a/description.xml b/description.xml
new file mode 100755 (executable)
index 0000000..65570f3
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<?xml-stylesheet type="text/xsl" href="description.xsl"?>\r
+<Overview version="1.0">\r
+  <SampleName>BluetoothChat</SampleName>\r
+  <SampleVersion>1.0.0</SampleVersion>\r
+  <Preview>bluetoothchat-snapshot.png</Preview>\r
+  <Description>\r
+         A sample application demonstrating the tizen device API usage.\r
+  </Description>\r
+</Overview>\r
diff --git a/description.xsl b/description.xsl
new file mode 100755 (executable)
index 0000000..1f4f57f
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+    This file provides a functionality to show template's description.xml in the project wizard.
+    Don't delete or move this file.
+ -->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:template match="/">
+    <html>
+      <head>
+        <style type="text/css">
+          html,body {
+          font-family:Arial;
+          margin: 0px;
+          }
+          td
+          {
+          font-size:13px;
+          }
+          .samplename
+          {
+          font-size:16px;
+          color:#ffffff;
+          height:26px;
+          background-color:#6d96ac;
+          }
+          .category
+          {
+          font-size:16px;
+          color:#ffffff;
+          height:30px;
+          background-color:#6d96ac;
+          }
+          .contents
+          {
+          padding: 6px 10px 14px 10px;
+          }
+          table#widgets td
+          {
+          border: solid 1px #6d96ac;
+          border-collapse: collapse;
+          }
+          .widgetname
+          {
+          font-weight: bold;
+          text-align: center;
+          width: 20%;
+          word-break:break-all;
+          }
+          table#references td
+          {
+          width: 100%;
+          border: 0px;
+          border-spacing: 0px;
+          padding: 5px;
+          }
+          .refname
+          {
+          width: 100%;
+          font-weight: bold;
+          }
+        </style>
+      </head>
+      <body>
+        <table width="400px" border="0" cellspacing="0">
+          <tr>
+            <td class="samplename" align="center">
+              <xsl:value-of select="Overview/SampleName"/>
+              <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
+                         <!--
+              <xsl:value-of select="Overview/SampleVersion"/>
+                         -->
+            </td>
+          </tr>
+          <tr bgcolor="#FFFFFF">
+            <td class="contents">
+                         <strong>Type</strong>: JavaScript
+                         <p>
+              <xsl:value-of select="Overview/Description"/>
+                         </p>
+            </td>
+          </tr>
+          <tr>
+            <td align="center" bgcolor="#FFFFFF" height="260px">
+              <img>
+                <xsl:attribute name="src">
+                  <xsl:value-of select="Overview/Preview"/>
+                </xsl:attribute>
+              </img>
+            </td>
+          </tr>
+        </table>
+      </body>
+    </html>
+  </xsl:template>
+
+</xsl:stylesheet>
diff --git a/project/.project b/project/.project
new file mode 100644 (file)
index 0000000..ea56a52
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>BluetoothChat</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.wst.common.project.facet.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>json.validation.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.tizen.web.jslint.nature.JSLintBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.tizen.web.css.nature.CSSBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.wst.validation.validationbuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.tizen.web.project.builder.WebBuilder</name>
+                       <arguments>
+                               <dictionary>
+                                       <key>usedLibraryType</key>
+                                       <value>WebUIFramework</value>
+                               </dictionary>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.tizen.web.privilege.nature.PrivilegeBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.tizen.web.editor.css.nature.CSSBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>json.validation.nature</nature>
+               <nature>org.tizen.web.jslint.nature.JSLintNature</nature>
+               <nature>org.tizen.web.css.nature.CSSNature</nature>
+               <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+               <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+               <nature>org.tizen.web.project.builder.WebNature</nature>
+               <nature>org.tizen.web.privilege.nature.PrivilegeNature</nature>
+               <nature>org.tizen.web.editor.css.nature.CSSNature</nature>
+       </natures>
+</projectDescription>
diff --git a/project/AUTHORS b/project/AUTHORS
new file mode 100644 (file)
index 0000000..4350a55
--- /dev/null
@@ -0,0 +1,7 @@
+Dariusz Paziewski <d.paziewski at samsung dot com>
+Tomasz Lukawski <t.lukawski at samsung dot com>
+Pawel Sierszen <p.sierszen at samsung dot com>
+Piotr Wronski <p.wronski at samsung dot com>
+Tomasz Paciorek <t.paciorek at samsung dot com>
+Artur Kobylinski <a.kobylinski at samsung dot com>
+Grzegorz Sala <g.sala2 at samsung dot com>
diff --git a/project/LICENSE.Flora b/project/LICENSE.Flora
new file mode 100644 (file)
index 0000000..4a0af40
--- /dev/null
@@ -0,0 +1,206 @@
+Flora License
+
+Version 1.1, April, 2013
+
+http://floralicense.org/license/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction,
+and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by
+the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and
+all other entities that control, are controlled by, or are
+under common control with that entity. For the purposes of
+this definition, "control" means (i) the power, direct or indirect,
+to cause the direction or management of such entity,
+whether by contract or otherwise, or (ii) ownership of fifty percent (50%)
+or more of the outstanding shares, or (iii) beneficial ownership of
+such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity
+exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications,
+including but not limited to software source code, documentation source,
+and configuration files.
+
+"Object" form shall mean any form resulting from mechanical
+transformation or translation of a Source form, including but
+not limited to compiled object code, generated documentation,
+and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form,
+made available under the License, as indicated by a copyright notice
+that is included in or attached to the work (an example is provided
+in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form,
+that is based on (or derived from) the Work and for which the editorial
+revisions, annotations, elaborations, or other modifications represent,
+as a whole, an original work of authorship. For the purposes of this License,
+Derivative Works shall not include works that remain separable from,
+or merely link (or bind by name) to the interfaces of, the Work and
+Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original
+version of the Work and any modifications or additions to that Work or
+Derivative Works thereof, that is intentionally submitted to Licensor
+for inclusion in the Work by the copyright owner or by an individual or
+Legal Entity authorized to submit on behalf of the copyright owner.
+For the purposes of this definition, "submitted" means any form of
+electronic, verbal, or written communication sent to the Licensor or
+its representatives, including but not limited to communication on
+electronic mailing lists, source code control systems, and issue
+tracking systems that are managed by, or on behalf of, the Licensor
+for the purpose of discussing and improving the Work, but excluding
+communication that is conspicuously marked or otherwise designated
+in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity
+on behalf of whom a Contribution has been received by Licensor and
+subsequently incorporated within the Work.
+
+"Tizen Certified Platform" shall mean a software platform that complies
+with the standards set forth in the Tizen Compliance Specification
+and passes the Tizen Compliance Tests as defined from time to time
+by the Tizen Technical Steering Group and certified by the Tizen
+Association or its designated agent.
+
+2. Grant of Copyright License.  Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the
+Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License.  Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+(except as stated in this section) patent license to make, have made,
+use, offer to sell, sell, import, and otherwise transfer the Work
+solely as incorporated into a Tizen Certified Platform, where such
+license applies only to those patent claims licensable by such
+Contributor that are necessarily infringed by their Contribution(s)
+alone or by combination of their Contribution(s) with the Work solely
+as incorporated into a Tizen Certified Platform to which such
+Contribution(s) was submitted. If You institute patent litigation
+against any entity (including a cross-claim or counterclaim
+in a lawsuit) alleging that the Work or a Contribution incorporated
+within the Work constitutes direct or contributory patent infringement,
+then any patent licenses granted to You under this License for that
+Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.  You may reproduce and distribute copies of the
+Work or Derivative Works thereof pursuant to the copyright license
+above, in any medium, with or without modifications, and in Source or
+Object form, provided that You meet the following conditions:
+
+  1. You must give any other recipients of the Work or Derivative Works
+     a copy of this License; and
+  2. You must cause any modified files to carry prominent notices stating
+     that You changed the files; and
+  3. You must retain, in the Source form of any Derivative Works that
+     You distribute, all copyright, patent, trademark, and attribution
+     notices from the Source form of the Work, excluding those notices
+     that do not pertain to any part of the Derivative Works; and
+  4. If the Work includes a "NOTICE" text file as part of its distribution,
+     then any Derivative Works that You distribute must include a readable
+     copy of the attribution notices contained within such NOTICE file,
+     excluding those notices that do not pertain to any part of
+     the Derivative Works, in at least one of the following places:
+     within a NOTICE text file distributed as part of the Derivative Works;
+     within the Source form or documentation, if provided along with the
+     Derivative Works; or, within a display generated by the Derivative Works,
+     if and wherever such third-party notices normally appear.
+     The contents of the NOTICE file are for informational purposes only
+     and do not modify the License. You may add Your own attribution notices
+     within Derivative Works that You distribute, alongside or as an addendum
+     to the NOTICE text from the Work, provided that such additional attribution
+     notices cannot be construed as modifying the License. You may add Your own
+     copyright statement to Your modifications and may provide additional or
+     different license terms and conditions for use, reproduction, or
+     distribution of Your modifications, or for any such Derivative Works
+     as a whole, provided Your use, reproduction, and distribution of
+     the Work otherwise complies with the conditions stated in this License
+     and your own copyright statement or terms and conditions do not conflict
+     the conditions stated in the License including section 3.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+any Contribution intentionally submitted for inclusion in the Work
+by You to the Licensor shall be under the terms and conditions of
+this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify
+the terms of any separate license agreement you may have executed
+with Licensor regarding such Contributions.
+
+6. Trademarks.  This License does not grant permission to use the trade
+names, trademarks, service marks, or product names of the Licensor,
+except as required for reasonable and customary use in describing the
+origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+agreed to in writing, Licensor provides the Work (and each
+Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied, including, without limitation, any warranties or conditions
+of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+PARTICULAR PURPOSE. You are solely responsible for determining the
+appropriateness of using or redistributing the Work and assume any
+risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+whether in tort (including negligence), contract, or otherwise,
+unless required by applicable law (such as deliberate and grossly
+negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special,
+incidental, or consequential damages of any character arising as a
+result of this License or out of the use or inability to use the
+Work (including but not limited to damages for loss of goodwill,
+work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses), even if such Contributor
+has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+the Work or Derivative Works thereof, You may choose to offer,
+and charge a fee for, acceptance of support, warranty, indemnity,
+or other liability obligations and/or rights consistent with this
+License. However, in accepting such obligations, You may act only
+on Your own behalf and on Your sole responsibility, not on behalf
+of any other Contributor, and only if You agree to indemnify,
+defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason
+of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Flora License to your work
+
+To apply the Flora License to your work, attach the following
+boilerplate notice, with the fields enclosed by brackets "[]"
+replaced with your own identifying information. (Don't include
+the brackets!) The text should be enclosed in the appropriate
+comment syntax for the file format. We also recommend that a
+file or class name and description of purpose be included on the
+same "printed page" as the copyright notice for easier
+identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Flora License, Version 1.1 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://floralicense.org/license/
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/project/NOTICE b/project/NOTICE
new file mode 100644 (file)
index 0000000..092bc04
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Flora License, Version 1.1
+Please, see the LICENSE.Flora file for Flora License, Version 1.1 terms and conditions.
+
diff --git a/project/config.xml b/project/config.xml
new file mode 100644 (file)
index 0000000..10ca79d
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets" id="http://sample-web-application.tizen.org/bt-chat" version="2.2.0" viewmodes="maximized">
+       <tizen:application id="QmwDyrmOzO.BluetoothChat" package="QmwDyrmOzO" required_version="2.2"/>
+       <content src="index.html"/>
+       <icon src="icon.png"/>
+       <name>Bluetooth Chat</name>
+       <feature name="http://tizen.org/feature/screen.size.normal.720.1280"/>
+       <tizen:privilege name="http://tizen.org/privilege/application.launch"/>
+       <tizen:privilege name="http://tizen.org/privilege/bluetooth.admin"/>
+       <tizen:privilege name="http://tizen.org/privilege/bluetooth.gap"/>
+       <tizen:privilege name="http://tizen.org/privilege/bluetooth.spp"/>
+       <tizen:privilege name="http://tizen.org/privilege/tizen"/>
+       <tizen:setting screen-orientation="portrait" context-menu="disable" background-support="disable" encryption="disable" install-location="auto"/>
+</widget>
diff --git a/project/css/style.css b/project/css/style.css
new file mode 100644 (file)
index 0000000..4e74a37
--- /dev/null
@@ -0,0 +1,184 @@
+html, body {
+       overflow: hidden;
+}
+
+.box {
+       margin: 0px;
+       padding: 0px;
+       display: table-cell;
+       vertical-align: middle;
+       height: inherit;
+       width: inherit;
+}
+
+#start-header .ui-btn-back {
+       width: 34px;
+}
+
+#chat-header .ui-btn-back {
+       width: 34px;
+}
+
+#chat-header .ui-btn-footer-down {
+       top: 19px;
+       right: 0px;
+}
+
+.ui-btn-start {
+       margin: 10px auto;
+       padding: 0;
+       width: 90%;
+       font-size: 26px;
+}
+
+.ui-btn-start > span {
+       padding-top: 30px;
+       padding-bottom: 30px;
+}
+
+/*
+#keyboard-text {
+       width: 100%;
+       margin: 0px;
+       padding: 0px;
+       border: 0px;
+       border-radius: 0px;
+       overflow: hidden;
+       font-size: 24px;
+       outline: none;
+}
+*/
+
+#keyboard-text {
+       width: 90%;
+       margin: 16px auto;
+}
+
+#keyboard-content .ui-scrollview-view {
+       padding: 0px;
+       text-align: center;
+}
+
+html {
+       background: white !important;
+}
+
+#start-content {
+       background-color: white;
+}
+
+#keyboard-content {
+       background-color: white;
+}
+
+#keyboard-back-button {
+       position: absolute;
+       right: 50px;
+       bottom: 15px;
+       width: 40px;
+}
+
+#ui-textArea {
+       position: absolute;
+       width: 100%;
+       height: 160px;
+       display: -webkit-box;
+       -webkit-box-orient: horizontal;
+}
+
+#ui-textArea-text {
+       -webkit-box-flex: 1;
+}
+
+#ui-textArea-button {
+       width: 100px;
+       height: 108px;
+}
+
+#text {
+       background-color: #fff;
+       color: #555;
+       position: absolute;
+       left: 10px;
+       right: 110px;
+       top: 10px;
+       height: 140px;
+       margin: 0px;
+       border: 0px solid #000;
+       border-radius: 5px;
+       font-size: 22px;
+       overflow: auto;
+}
+
+#ui-mySend {
+       float: left;
+       width: 85px;
+       margin-top: 10px;
+       font-size: 22px;
+}
+
+#ui-myCounter {
+       float: left;
+       margin-top: 47px;
+}
+
+#ui-myCounter p {
+       font-size: 20px;
+}
+
+#chat-footer {
+       height: 164px;
+}
+
+#start-monit {
+       text-align: center;
+       width: 100%;
+}
+
+#start-monit a {
+       font-size: 1.4em;
+}
+
+#chat-header {
+       min-height: 2.5em;
+}
+
+#chat-header-type {
+       font-size: 0.5em;
+       position: absolute;
+       top: 3px;
+       left: 3px;
+       white-space: nowrap;
+       overflow: hidden !important;
+       text-overflow: ellipsis;
+       width: 90%;
+}
+
+#chat-header-name {
+       font-size: 1em;
+       position: absolute;
+       top: 25px;
+       left: 3px;
+       white-space: nowrap;
+       overflow: hidden !important;
+       text-overflow: ellipsis;
+       width: 60%;
+}
+
+.server-row-name {
+       white-space: nowrap;
+       overflow: hidden !important;
+       text-overflow: ellipsis;
+       width: 80%;
+}
+
+#discovering {
+       right: 8px;
+       top: 8px;
+}
+
+.focus {}
+
+.ui-btn-back {
+       visibility:hidden;
+}
diff --git a/project/icon.png b/project/icon.png
new file mode 100644 (file)
index 0000000..5934757
Binary files /dev/null and b/project/icon.png differ
diff --git a/project/index.html b/project/index.html
new file mode 100644 (file)
index 0000000..974a9f5
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+       <meta charset="utf-8"/>
+       <meta name="description" content="bt-chat"/>
+       <meta name="viewport" content="width=360, user-scalable=no"/>
+
+       <title>Bluetooth chat</title>
+       <script src="tizen-web-ui-fw/latest/js/jquery.min.js"></script>
+       <script src="tizen-web-ui-fw/latest/js/tizen-web-ui-fw-libs.min.js"></script>
+       <script src="tizen-web-ui-fw/latest/js/tizen-web-ui-fw.min.js" data-framework-theme="tizen-white" data-framework-viewport-scale="false"></script>
+
+       <script type="text/javascript" src="./js/main.js"></script>
+       <link rel="stylesheet" type="text/css" href="./css/style.css"/>
+</head>
+
+<body>
+       <div id="start" data-role="page">
+               <div id="start-header" data-role="header" data-position="fixed">
+                       <h1>Bluetooth chat</h1>
+               </div>
+
+               <div id="start-content" data-role="content" data-scroll="none">
+                       <div class="box">
+                               <div data-role="button" class="ui-btn-start" id="turnOnButton" style="display: none;">Turn bluetooth on</div>
+                               <div data-role="button" class="ui-btn-start" id="serverButton" style="display: none;">Create server</div>
+                               <div data-role="button" class="ui-btn-start" id="clientButton" style="display: none;">Join server</div>
+                               <div id="start-monit" style="display: none;">
+                                       <p>Waiting for Bluetooth...</p>
+                               </div>
+                       </div>
+               </div>
+       </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/project/js/app.client.js b/project/js/app.client.js
new file mode 100644 (file)
index 0000000..10dd388
--- /dev/null
@@ -0,0 +1,112 @@
+/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */
+/*global $, tizen, app, ClientModel */
+/**
+ * @class Client
+ */
+
+function Client(adapter, serviceUUID) {
+       'use strict';
+       this.adapter = adapter;
+       this.serviceUUID = serviceUUID;
+       this.globalSocket = null;
+       this.init();
+       this.discovering = false;
+       this.chatServerDevice = null;
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+
+       Client.prototype = {
+               /**
+                * @type clientModel
+                */
+               model: null,
+
+               /**
+                * Initialisation function
+                */
+               init: function Client_init() {
+                       this.model = new ClientModel(this);
+                       return this;
+               },
+
+               setDiscovering: function Client_setDiscovering(boolean) {
+                       this.discovering = boolean;
+                       app.ui.setDiscoveringProgress(boolean);
+               },
+
+               getDiscovering: function Client_getDiscovering() {
+                       return this.discovering;
+               },
+
+               searchServer: function Client_searchServer() {
+                       this.model.searchServer();
+               },
+
+               addDeviceToList: function Client_addDeviceToList(device) {
+                       app.ui.addDeviceToList(device);
+               },
+
+               stopServerSearching: function Client_stopServerSearching(address) {
+                       if (address !== undefined) {
+                               this.model.stopServerSearching(this.startBonding.bind(this, address, this.connectToService.bind(this)));
+                       } else {
+                               this.model.stopServerSearching();
+                       }
+               },
+
+               startBonding: function Client_startBonding(address, callback) {
+                       this.model.startBonding(address, callback);
+               },
+
+               connectToService: function Client_connectToService(device) {
+                       this.model.connectToService(device, this.serviceUUID, this.connectToServiceSuccess.bind(this, device), this.connectToServiceError.bind(this));
+               },
+
+               connectToServiceSuccess: function Client_connectToServiceSuccess(device, socket) {
+                       this.globalSocket = socket;
+                       socket.onmessage = function () {
+                               var data, recvmsg = '', i, len, messageObj;
+                               data = socket.readData();
+                               len = data.length;
+                               for (i = 0; i < len; i += 1) {
+                                       recvmsg += String.fromCharCode(data[i]);
+                               }
+                               messageObj = JSON.parse(recvmsg);
+                               app.ui.displayReceivedMessage(messageObj.name, messageObj.text, messageObj.ping, messageObj.bye);
+                       };
+                       socket.onerror = function (e) {
+                               console.error('Client onerror');
+                               socket.close();
+                       };
+                       socket.onclose = function () {
+                               this.globalSocket = null;
+                               app.setConnection(false);
+                       };
+                       app.setConnection(true);
+                       app.ui.showChatPage(device.name);
+                       this.sendPing();
+               },
+
+               connectToServiceError: function Client_connectToServiceError(error) {
+                       console.error('Client_connectToServiceError: ' + error.message);
+               },
+
+               sendPing: function Client_sendPing() {
+                       this.model.sendPing(this.adapter.name, this.globalSocket);
+               },
+
+               sendMessage: function Client_sendMessage(message, callback) {
+                       this.model.sendMessage(this.adapter.name, this.globalSocket, message, callback);
+               },
+
+               sendBye: function Client_sendBye() {
+                       this.model.sendBye(this.adapter.name, this.globalSocket);
+               },
+
+               destroyBonding: function Client_destroyBonding() {
+                       this.model.destroyBonding(this.chatServerDevice, app.restartBluetooth.bind(app), app.ui.showStartButtons);
+               }
+       };
+}());
diff --git a/project/js/app.client.model.js b/project/js/app.client.model.js
new file mode 100644 (file)
index 0000000..8b5960e
--- /dev/null
@@ -0,0 +1,141 @@
+/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */
+/*global $, tizen, app */
+/**
+ * @class Model
+ */
+function ClientModel(parent) {
+       'use strict';
+       this.client = parent;
+       this.init();
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       ClientModel.prototype = {
+
+               /**
+                * API module initialisation
+                */
+               init: function ClientModel_init() {},
+
+               searchServer: function ClientModel_searchServer() {
+                       var discoverDevicesSuccessCallback = {
+                               onstarted: function () {
+                                       this.client.setDiscovering(true);
+                               }.bind(this),
+                               ondevicefound: function (device) {
+                                       this.client.addDeviceToList(device);
+                               }.bind(this),
+                               ondevicedisappeared: function (address) {},
+                               onfinished: function (devices) {
+                                       this.client.setDiscovering(false);
+                               }.bind(this)
+                       };
+
+                       this.client.adapter.discoverDevices(discoverDevicesSuccessCallback, function (e) { this.client.setDiscovering(false); });
+               },
+
+               stopServerSearching: function ClientModel_stopServerSearching(callback) {
+                       if (this.client.getDiscovering()) {
+                               this.client.adapter.stopDiscovery(function () {
+                                       this.client.setDiscovering(false);
+                                       if (typeof callback === 'function') {
+                                               callback();
+                                       }
+                               }.bind(this), function (e) {
+                                       console.error("Error while stopDiscovery:" + e.message);
+                               });
+                       } else if (typeof callback === 'function') {
+                               callback();
+                       }
+               },
+
+               startBonding: function ClientModel_startBonding(address, callback) {
+                       this.client.adapter.createBonding(address, function (device) { callback(device); }, function (error) { console.error('bondError: ' + error.message); });
+               },
+
+               connectToService: function ClientModel_connectToService(device, serviceUUID, successCallback, errorCallback) {
+                       this.client.chatServerDevice = device;
+                       try {
+                               device.connectToServiceByUUID(serviceUUID, successCallback, errorCallback);
+                       } catch (error) {
+                               console.error('connectToServiceByUUID ERROR: ' + error.message);
+                       }
+               },
+
+               sendPing: function ClientModel_sendPing(name, socket) {
+                       var sendTextMsg, messageObj, messageObjToString, i, len;
+                       sendTextMsg = [];
+                       messageObj = {name: encodeURIComponent(name), text: '', ping: true, bye: false};
+                       messageObjToString = JSON.stringify(messageObj);
+                       len = messageObjToString.length;
+
+                       for (i = 0; i < len; i += 1) {
+                               sendTextMsg[i] = messageObjToString.charCodeAt(i);
+                       }
+                       try {
+                               if (socket !== null && socket.state === "OPEN") {
+                                       socket.writeData(sendTextMsg);
+                               }
+                       } catch (error) {
+                               console.error('sendPing: ' + error.message);
+                       }
+               },
+
+               sendMessage: function ClientModel_sendMessage(name, socket, message, callback) {
+                       var sendTextMsg = [], messageObj, messageObjToString, i, len;
+                       name = encodeURIComponent(name);
+                       message = encodeURIComponent(message);
+                       messageObj = {name: name, text: message, ping: false, bye: false};
+                       messageObjToString = JSON.stringify(messageObj);
+                       len = messageObjToString.length;
+                       for (i = 0; i < len; i += 1) {
+                               sendTextMsg[i] = messageObjToString.charCodeAt(i);
+                       }
+                       try {
+                               if (socket !== null && socket.state === "OPEN") {
+                                       socket.writeData(sendTextMsg);
+                                       callback(message);
+                               }
+                       } catch (error) {
+                               console.error('sendMessage: ' + error.message);
+                       }
+               },
+
+               sendBye: function ClientModel_sendBye(name, socket) {
+                       var sendTextMsg = [], messageObj, messageObjToString, i, len;
+                       name = encodeURIComponent(name);
+                       messageObj = {name: name, text: '', ping: false, bye: true};
+                       messageObjToString = JSON.stringify(messageObj);
+                       len = messageObjToString.length;
+                       for (i = 0; i < len; i += 1) {
+                               sendTextMsg[i] = messageObjToString.charCodeAt(i);
+                       }
+                       try {
+                               if (socket !== null && socket.state === "OPEN") {
+                                       socket.writeData(sendTextMsg);
+                               }
+                       } catch (error) {
+                               console.error('sendBye: ' + error.message);
+                       }
+               },
+
+               destroyBonding: function ClientModel_destroyBonding(device, restartCallback, showStartButtonsCallback) {
+                       if (device !== null) {
+                               if (device.isBonded) {
+                                       this.client.adapter.destroyBonding(device.address, function () {
+                                               device = null;
+                                               restartCallback();
+                                       }, function (error) { console.error('ClientModel_destroyBonding: ' + error); });
+                               } else {
+                                       device = null;
+                                       restartCallback();
+                               }
+                       } else {
+                               this.stopServerSearching();
+                               showStartButtonsCallback();
+                       }
+               }
+
+       };
+}());
diff --git a/project/js/app.config.js b/project/js/app.config.js
new file mode 100644 (file)
index 0000000..c40c601
--- /dev/null
@@ -0,0 +1,29 @@
+/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */
+/*global $, tizen, app */
+/**
+ * @class Config
+ */
+function Config() {
+       'use strict';
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Config.prototype = {
+
+               properties: {
+                       'templateDir': 'templates',
+                       'templateExtension': '.tpl'
+               },
+
+               /**
+                * Returns config value
+                */
+               get: function (value, defaultValue) {
+                       if (this.properties.hasOwnProperty(value)) {
+                               return this.properties[value];
+                       }
+                       return defaultValue;
+               }
+       };
+}());
diff --git a/project/js/app.helpers.js b/project/js/app.helpers.js
new file mode 100644 (file)
index 0000000..0437bc6
--- /dev/null
@@ -0,0 +1,19 @@
+/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */
+/*global $, tizen, app */
+/**
+ * @class Helpers
+ */
+function Helpers() {
+       'use strict';
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Helpers.prototype = {
+
+               checkStringLength: function Helpers_checkStringLength(value) {
+                       return value.length > 0 ? true : false;
+               }
+
+       };
+}());
diff --git a/project/js/app.js b/project/js/app.js
new file mode 100644 (file)
index 0000000..c02479e
--- /dev/null
@@ -0,0 +1,213 @@
+/*global $, tizen, app, Config, Helpers, Model, Ui, Server, Client */
+var App = null;
+
+(function () { // strict mode wrapper
+       'use strict';
+
+       /**
+        * Creates a new application object
+        *
+        * @class Application
+        */
+       App = function App() {};
+
+       App.prototype = {
+               /**
+                * @type Array
+                */
+               requires: ['js/app.config.js',
+                          'js/app.helpers.js',
+                          'js/app.model.js',
+                          'js/app.ui.js',
+                          'js/app.ui.templateManager.js',
+                          'js/app.ui.events.js',
+                          'js/app.client.js',
+                          'js/app.client.model.js',
+                          'js/app.server.js',
+                          'js/app.server.model.js'
+                          ],
+
+               /**
+                * @type Model
+                */
+               model: null,
+
+               /**
+                * @type Ui
+                */
+               ui: null,
+
+               /**
+                * @type Config
+                */
+               config: null,
+
+               /**
+                * @type Helpers
+                */
+               helpers: null,
+
+               /**
+                * @type Client
+                */
+               client: null,
+
+               /**
+                * @type Server
+                */
+               server: null,
+
+               /**
+                * @type String
+                */
+               currentName: '',
+
+               /**
+                * @type Boolean
+                */
+               doNotSendBye: false,
+
+               /**
+                * @type Boolean
+                */
+               connection: false,
+
+               /**
+                * Initialisation function
+                */
+               init: function App_init() {
+                       this.config = new Config();
+                       this.helpers = new Helpers();
+                       this.model = new Model();
+                       this.ui = new Ui(this.initModel.bind(this));
+               },
+
+               initModel: function App_initModel() {
+                       this.model.init(this.checkPowerState.bind(this));
+               },
+
+               /**
+                * exit application action
+                */
+               exit: function App_exit() {
+                       tizen.application.getCurrentApplication().exit();
+               },
+
+               isConnection: function App_isConnection() {
+                       return this.connection;
+               },
+
+               setConnection: function App_setConnection(bool) {
+                       this.connection = bool;
+               },
+
+               getDoNotSendBye: function App_getDoNotSendBye() {
+                       return this.doNotSendBye;
+               },
+
+               setDoNotSendBye: function App_setDoNotSendBye(bool) {
+                       this.doNotSendBye = bool;
+               },
+
+               getCurrentName: function App_getCurrentName() {
+                       return this.currentName;
+               },
+
+               getApplicationMode: function App_getApplicationMode() {
+                       var mode = 'start';
+                       if (this.client !== null) {
+                               mode = 'client';
+                       } else if (this.server !== null) {
+                               mode = 'server';
+                       }
+                       return mode;
+               },
+
+               resetApplicationMode: function App_resetApplicationMode() {
+                       this.client = null;
+                       this.server = null;
+               },
+
+               checkPowerState: function App_checkPowerState() {
+                       this.ui.setContentStartAttributes(
+                               this.model.checkPowerState.bind(
+                                       this.model,
+                                       this.ui.showPowerOnButton,
+                                       this.ui.showStartButtons
+                               )
+                       );
+               },
+
+               powerOn: function App_powerOn() {
+                       this.model.powerOn(this.ui.showStartButtons);
+               },
+
+               powerOff: function App_powerOff() {
+                       this.model.powerOff(this.exit);
+               },
+
+               restartBluetooth: function App_restartBluetooth() {
+                       this.model.restartBluetooth(this.powerOn.bind(this));
+               },
+
+               startServer: function App_startServer() {
+                       this.server = new Server(this.model.adapter, this.model.serviceUUID);
+                       this.showKeyboardPage();
+               },
+
+               startClient: function App_startClient() {
+                       this.client = new Client(this.model.adapter, this.model.serviceUUID);
+                       this.showKeyboardPage();
+               },
+
+               showKeyboardPage: function App_showKeyboardPage() {
+                       this.ui.showKeyboardPage();
+               },
+
+               setUserName: function App_setUserName(value) {
+                       this.currentName = value;
+               },
+
+               setAdapterName: function App_setAdapterName() {
+                       var changeName = false, mode = this.getApplicationMode();
+                       if (this.model.adapter.name !== this.currentName) {
+                               changeName = true;
+                       }
+                       if (mode === 'server') {
+                               this.model.setAdapterName(changeName, this.server.registerServer.bind(this.server));
+                       } else if (mode === 'client') {
+                               this.model.setAdapterName(changeName, this.client.searchServer.bind(this.client));
+                       }
+               },
+
+               isBluetoothVisible: function App_isBluetoothVisible() {
+                       return this.model.adapter.visible;
+               },
+
+               clearListOfServers: function App_clearListOfServers() {
+                       this.ui.clearListOfServers();
+               },
+
+               displaySentMessage: function App_displaySentMessage(message) {
+                       this.ui.displaySentMessage(message);
+               },
+
+               sendMessage: function App_sendMessage(message) {
+                       var mode = this.getApplicationMode();
+                       if (mode === 'server') {
+                               this.server.sendMessage(message, this.displaySentMessage.bind(this));
+                       } else if (mode === 'client') {
+                               this.client.sendMessage(message, this.displaySentMessage.bind(this));
+                       }
+               },
+
+               sendBye: function App_sendBye() {
+                       var mode = this.getApplicationMode();
+                       if (mode === 'server') {
+                               this.server.sendBye();
+                       } else if (mode === 'client') {
+                               this.client.sendBye();
+                       }
+               }
+       };
+}());
diff --git a/project/js/app.model.js b/project/js/app.model.js
new file mode 100644 (file)
index 0000000..9cf77a4
--- /dev/null
@@ -0,0 +1,85 @@
+/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */
+/*global $, tizen, app */
+/**
+ * @class Model
+ */
+function Model() {
+       'use strict';
+       this.adapter = null;
+       this.serviceUUID = '5BCE9431-6C75-32AB-AFE0-2EC108A30860';
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Model.prototype = {
+
+               /**
+                * API module initialisation
+                */
+               init: function Model_init(callback) {
+                       try {
+                               console.log('getDefaultAdapter');
+                               var time = new Date().getTime();
+                               this.adapter = tizen.bluetooth.getDefaultAdapter();
+                               console.log('getDefaultAdapter OK: ' + (new Date().getTime() - time) + ' milliseconds.');
+                               callback();
+                       } catch (error) {
+                               app.ui.showMessagePopup('Problem with bluetooth device. Application can\'t work properly: ' + error.message);
+                               tizen.application.getCurrentApplication().exit();
+                       }
+               },
+
+               checkPowerState: function Model_checkPowerState(showPowerOnButtonCallback, showStartButtonsCallback) {
+                       if (!this.adapter.powered) {
+                               showPowerOnButtonCallback();
+                       } else {
+                               showStartButtonsCallback();
+                       }
+               },
+
+               powerOn: function Model_powerOn(callback) {
+                       if (!this.adapter.powered) {
+                               try {
+                                       this.adapter.setPowered(true,
+                                               function () {
+                                                       setTimeout(function () { callback(); }, 500);
+                                               }
+                                       );
+                               } catch (error) {
+                                       app.ui.showMessagePopup(error.message);
+                                       app.ui.showPowerOnButton();
+                               }
+                       } else {
+                               callback();
+                       }
+               },
+
+               powerOff: function Model_powerOff(callback) {
+                       var app = tizen.application.getCurrentApplication();
+                       if (this.adapter.powered) {
+                               this.adapter.setPowered(false, function () { callback(); }, function () { callback(); });
+                       } else {
+                               callback();
+                       }
+               },
+
+               restartBluetooth: function Model_restartBluetooth(callback) {
+                       if (this.adapter.powered) {
+                               this.adapter.setPowered(false, function () { setTimeout(function () { callback(); }, 500); }, function () {});
+                       } else {
+                               callback();
+                       }
+               },
+
+               setAdapterName: function Model_setAdapterName(changeName, callback) {
+                       if (changeName) {
+                               this.adapter.setName(app.currentName, function () {
+                                       callback();
+                               }, function () {
+                               });
+                       } else {
+                               callback();
+                       }
+               }
+       };
+}());
diff --git a/project/js/app.server.js b/project/js/app.server.js
new file mode 100644 (file)
index 0000000..6cf5c5a
--- /dev/null
@@ -0,0 +1,93 @@
+/*global $, tizen, app, ServerModel */
+/**
+ * @class Server
+ */
+
+function Server(adapter, serviceUUID) {
+       'use strict';
+       this.adapter = adapter;
+       this.serviceUUID = serviceUUID;
+       this.numberOfClients = 0;
+       this.globalRecordHandler = null;
+       this.globalSocket = null;
+       this.init();
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+
+       Server.prototype = {
+               /**
+                * @type clientModel
+                */
+               model: null,
+
+               /**
+                * Initialisation function
+                */
+               init: function Server_init() {
+                       this.model = new ServerModel(this);
+                       return this;
+               },
+
+               getNumberOfClients: function Server_getNumberOfClients() {
+                       return this.numberOfClients;
+               },
+
+               registerServer: function Server_registerServer() {
+                       this.model.registerServer(this.adapter, this.serviceUUID, this.registerServerSuccess.bind(this));
+               },
+
+               registerServerSuccess: function Server_registerServerSuccess(recordHandler) {
+                       this.globalRecordHandler = recordHandler;
+                       recordHandler.onconnect = function (socket) {
+                               this.numberOfClients += 1;
+                               this.globalSocket = socket;
+                               socket.onmessage = function () {
+                                       var data, recvmsg = '', i, len, messageObj;
+                                       data = socket.readData();
+                                       len = data.length;
+                                       for (i = 0; i < len; i += 1) {
+                                               recvmsg += String.fromCharCode(data[i]);
+                                       }
+                                       messageObj = JSON.parse(recvmsg);
+                                       app.ui.displayReceivedMessage(messageObj.name, messageObj.text, messageObj.ping, messageObj.bye);
+                               };
+                               socket.onerror = function (e) {
+                                       console.error('Server onerror');
+                                       socket.close();
+                               };
+                               socket.onclose = function () {
+                                       this.globalSocket = null;
+                                       app.setConnection(false);
+                               };
+                               app.setConnection(true);
+                       }.bind(this);
+                       app.ui.showChatPage();
+               },
+
+               unregisterChatServer: function Server_unregisterChatServer() {
+                       this.model.unregisterChatServer(this.globalRecordHandler, this.unregisterChatServerSuccess.bind(this), this.unregisterChatServerError.bind(this), app.ui.showStartButtons);
+               },
+
+               unregisterChatServerSuccess: function Server_unregisterChatServerSuccess() {
+                       this.globalRecordHandler = null;
+                       this.numberOfClients = 0;
+                       app.restartBluetooth();
+               },
+
+               unregisterChatServerError: function Server_unregisterChatServerError() {
+                       console.error('Server_unregisterChatServerError');
+                       this.numberOfClients = 0;
+                       app.restartBluetooth();
+               },
+
+               sendMessage: function Server_sendMessage(message, callback) {
+                       this.model.sendMessage(this.adapter.name, this.globalSocket, message, callback);
+               },
+
+               sendBye: function Server_sendBye() {
+                       this.model.sendBye(this.adapter.name, this.globalSocket);
+               }
+       };
+}());
diff --git a/project/js/app.server.model.js b/project/js/app.server.model.js
new file mode 100644 (file)
index 0000000..771353e
--- /dev/null
@@ -0,0 +1,81 @@
+/*global $, tizen, app */
+/**
+ * @class Model
+ */
+function ServerModel(parent) {
+       'use strict';
+       this.server = parent;
+       this.init();
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       ServerModel.prototype = {
+
+               /**
+                * API module initialisation
+                */
+               init: function ServerModel_init() {},
+
+               registerServer: function ServerModel_registerServer(adapter, serviceUUID, callback) {
+                       if (this.server.getNumberOfClients() === 0) {
+                               try {
+                                       adapter.registerRFCOMMServiceByUUID(serviceUUID, 'Chat service', callback, function (error) { console.error(error.message); });
+                               } catch (error) {
+                                       console.error(error.message);
+                               }
+                       }
+               },
+
+               unregisterChatServer: function ServerModel_unregisterChatServer(globalRecordHandler, successCallback, errorCallback, showButtonsCallback) {
+                       try {
+                               if (globalRecordHandler !== null) {
+                                       globalRecordHandler.unregister(successCallback, errorCallback);
+                               } else {
+                                       showButtonsCallback();
+                               }
+                       } catch (error) {
+                               errorCallback();
+                       }
+               },
+
+               sendMessage: function ServerModel_sendMessage(name, socket, message, callback) {
+                       var sendTextMsg = [], messageObj, messageObjToString, i, len;
+                       name = encodeURIComponent(name);
+                       message = encodeURIComponent(message);
+                       messageObj = {name: name, text: message, ping: false, bye: false};
+                       messageObjToString = JSON.stringify(messageObj);
+                       len = messageObjToString.length;
+                       for (i = 0; i < len; i += 1) {
+                               sendTextMsg[i] = messageObjToString.charCodeAt(i);
+                       }
+                       try {
+                               if (socket !== null && socket.state === "OPEN") {
+                                       socket.writeData(sendTextMsg);
+                                       callback(message);
+                               }
+                       } catch (error) {
+                               console.error('sendMessage: ' + error.message);
+                       }
+               },
+
+               sendBye: function ServerModel_sendBye(name, socket) {
+                       var sendTextMsg = [], messageObj, messageObjToString, i, len;
+                       name = encodeURIComponent(name);
+                       messageObj = {name: name, text: '', ping: false, bye: true};
+                       messageObjToString = JSON.stringify(messageObj);
+                       len = messageObjToString.length;
+                       for (i = 0; i < len; i += 1) {
+                               sendTextMsg[i] = messageObjToString.charCodeAt(i);
+                       }
+                       try {
+                               if (socket !== null && socket.state === "OPEN") {
+                                       socket.writeData(sendTextMsg);
+                               }
+                       } catch (error) {
+                               console.error('sendBye: ' + error.message);
+                       }
+               }
+
+       };
+}());
diff --git a/project/js/app.ui.events.js b/project/js/app.ui.events.js
new file mode 100644 (file)
index 0000000..f9ae99f
--- /dev/null
@@ -0,0 +1,214 @@
+/*global $, tizen, app */
+/**
+ * @class UiEvents
+ */
+function UiEvents(parent) {
+       'use strict';
+       this.ui = parent;
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       UiEvents.prototype = {
+
+               /**
+                * Initialization
+                */
+               init: function UiEvents_init() {
+                       this.addPageEvents();
+               },
+
+               /**
+                * Bind events to pages
+                */
+               addPageEvents: function UiEvents_addPageEvents() {
+                       var self = this;
+
+                       $('#start-header .ui-btn-back').on('click', function (event) {
+                               event.preventDefault();
+                               event.stopPropagation();
+                               app.powerOff();
+                       });
+
+                       $('#choose-footer').on('click', '.ui-btn-back', function (event) {
+                               event.preventDefault();
+                               event.stopPropagation();
+                               app.setDoNotSendBye(true);
+                               $.mobile.changePage('#start');
+                       });
+
+                       $('#chat-header').on('click', '.ui-btn-back', function (event) {
+                               event.preventDefault();
+                               event.stopPropagation();
+                               if (!app.isConnection()) {
+                                       app.setDoNotSendBye(true);
+                               }
+                               $.mobile.changePage('#start');
+                       });
+
+                       $('#chat-header').on('click', '.ui-btn-back', function (event) {
+                               event.preventDefault();
+                       });
+
+                       $('#start').on('pagebeforeshow', function () {
+                               self.ui.hideStartButtons();
+                               self.ui.clearChatDialog();
+                               if (!app.getDoNotSendBye()) {
+                                       app.sendBye();
+                               } else {
+                                       app.setDoNotSendBye(false);
+                               }
+                               if (app.getApplicationMode() === 'server') {
+                                       app.server.unregisterChatServer();
+                               } else if (app.getApplicationMode() === 'client') {
+                                       app.client.destroyBonding();
+                               }
+                       });
+
+                       $('#turnOnButton').on('click', function (event) {
+                               self.ui.hideStartButtons();
+                               app.powerOn();
+                       });
+
+                       $('#serverButton').on('click', function (event) {
+                               app.resetApplicationMode();
+                               app.startServer();
+                       });
+
+                       $('#clientButton').on('click', function (event) {
+                               app.resetApplicationMode();
+                               app.startClient();
+                       });
+
+                       $('#keyboard').on('pagebeforeshow', function () {
+                               $('#keyboard-text').val('').attr('placeholder', 'Type ' + app.getApplicationMode() + ' name');
+                               $('#keyboard-header > h1').html('Type ' + app.getApplicationMode() + ' name');
+                       });
+
+                       $('#keyboard').on('pageshow', function () {
+                               setTimeout(function () { $('#keyboard-text').focus(); }, 500);
+                       });
+
+                       $('#keyboard-ok-button').on('click', function (event) {
+                               event.preventDefault();
+                               var value = $('#keyboard-text').val(), mode;
+                               if (value.length !== 0) {
+                                       app.setUserName(value);
+                                       mode = app.getApplicationMode();
+                                       if (mode === 'server') {
+                                               app.setAdapterName();
+                                       } else if (mode === 'client') {
+                                               $.mobile.changePage('#choose');
+                                       }
+                               }
+                       });
+
+                       $('#choose').on('pagebeforeshow', function () {
+                               app.setAdapterName();
+                       });
+
+                       $('#choose').on('pagehide', function () {
+                               app.clearListOfServers();
+                               app.client.stopServerSearching();
+                       });
+
+                       $('#choose-content').on('click', 'ul.ui-listview li', function () {
+                               app.client.stopServerSearching($(this).attr('address'));
+                       });
+
+                       $('#chat').on('pagebeforeshow', function () {
+                               $('#chat-header-type').html(app.getApplicationMode());
+                               $('#chat-header-name').html(app.getCurrentName());
+                               if ($(this).data('serverName') !== undefined) {
+                                       $('#chat-header-type').append(' - connected to ' + $(this).data('serverName'));
+                                       $(this).removeData('serverName');
+                               }
+                               self.ui.checkSendButtonState();
+                       });
+
+                       $('#chat').on('pageshow', function () {
+                               if (app.getApplicationMode() === 'server' && !app.isBluetoothVisible()) {
+                                       setTimeout(function () { app.ui.showMessagePopup('Please make your Bluetooth visible in Settings.'); }, 500);
+                               }
+                       });
+
+                       $('#chat').on('pagehide', function () {
+                               $('#text').val('');
+                               app.setConnection(false);
+                       });
+
+                       $('#text').on('input', function () {
+                               self.ui.checkSendButtonState();
+                       });
+
+                       $('#text').on('focus', function () {
+                               var content = $('#chat-content');
+                               if (self.ui.scrolltimeout !== null) {
+                                       clearTimeout(self.ui.scrolltimeout);
+                               }
+                               self.ui.scrolltimeout = setTimeout(function () {
+                                       self.ui.scrolltimeout = null;
+                                       self.ui.scrollToBottom(content);
+                               }, 1000);
+                       });
+
+                       $('#text').on('blur', function () {
+                               var content = $('#chat-content');
+                               if (self.ui.scrolltimeout !== null) {
+                                       clearTimeout(self.ui.scrolltimeout);
+                               }
+                               self.ui.scrolltimeout = setTimeout(function () {
+                                       self.ui.scrolltimeout = null;
+                                       self.ui.scrollToBottom(content);
+                               }, 700);
+                       });
+
+                       $('#ui-mySend').on('click', function (event) {
+                               event.stopPropagation();
+                               var message = $('#text').val();
+                               $('#text').val('');
+                               self.ui.disableSendButton();
+                               app.sendMessage(message);
+                       });
+
+                       $('body').on('click', '#byeOK', function () {
+                               self.ui.hideByePopup();
+                               $('#keyboard-back-button').trigger('click');
+                       });
+
+                       $('body').on('touchstart', '#byePopup-screen', function () {
+                               $('#byeOK').trigger('click');
+                       });
+
+                       $('body').on('click', '#messageOK', function () {
+                               self.ui.hideMessagePopup();
+                       });
+
+                       $('body').on('touchstart', '#messagePopup-screen', function () {
+                               $('#messageOK').trigger('click');
+                       });
+
+                       $('#chat-content').on('touchstart', function () {
+                               if (self.ui.scrolltimeout !== null) {
+                                       clearTimeout(self.ui.scrolltimeout);
+                                       self.ui.scrolltimeout = null;
+                               }
+                       });
+
+                       window.addEventListener('tizenhwkey', function(e) {
+                               if (e.keyName == "back") {
+                                       event.preventDefault();
+                                       app.setDoNotSendBye(true);
+                                       if ($.mobile.activePage.attr('id') === 'start') {
+                                               tizen.application.getCurrentApplication().exit();
+                                       } else if ($.mobile.activePage.attr('id') === 'chat') {
+                                               $.mobile.changePage('#start');
+                                       } else {
+                                               history.back();
+                                       }
+                               }
+                       });
+
+               }
+       };
+}());
diff --git a/project/js/app.ui.js b/project/js/app.ui.js
new file mode 100644 (file)
index 0000000..9bd9d99
--- /dev/null
@@ -0,0 +1,245 @@
+/*global $, tizen, app, UiEvents, TemplateManager, document, window, setTimeout */
+/**
+ * @class Ui
+ */
+
+function Ui(callback) {
+       'use strict';
+       this.init(callback);
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Ui.prototype = {
+
+               templateManager: null,
+
+               /**
+                * UI object for UI events
+                */
+               uiEvents: null,
+
+               /**
+                * Timeout for chat scroll.
+                */
+               scrolltimeout: null,
+
+               /**
+                * UI module initialisation
+                */
+               init: function Ui_init(callback) {
+                       this.templateManager = new TemplateManager();
+                       this.uiEvents = new UiEvents(this);
+                       $.mobile.tizen.disableSelection(document);
+
+                       $(document).ready(this.domInit.bind(this, callback));
+               },
+
+               /**
+                * When DOM is ready, initialise it (bind events)
+                */
+               domInit: function Ui_domInit(callback) {
+                       var templates = [
+                               'keyboard_page',
+                               'chat_page',
+                               'choose_page',
+                               'server_row',
+                               'left_bubble',
+                               'right_bubble',
+                               'bye_popup',
+                               'message_popup'
+                       ];
+
+                       this.templateManager.loadToCache(templates, this.initPages.bind(this, callback));
+               },
+
+               initPages: function Ui_initPages(callback) {
+                       var pages = [], body = $('body');
+
+                       body.append(this.templateManager.get('bye_popup'))
+                               .append(this.templateManager.get('message_popup'))
+                               .trigger('create');
+
+                       pages.push(this.templateManager.get('keyboard_page'));
+                       pages.push(this.templateManager.get('chat_page'));
+                       pages.push(this.templateManager.get('choose_page'));
+                       body.append(pages.join(''));
+
+                       this.uiEvents.init();
+                       this.fixContentHeight();
+                       callback();
+               },
+
+               setContentStartAttributes: function Ui_setContentStartAttributes(callback) {
+                       var contentStart, contentStartHeight;
+                       contentStart = $('#start-content');
+                       if (contentStart.height() > $(window).height()) {
+                               contentStartHeight = $(window).height() - $('#start-header').height()
+                                       - parseInt(contentStart.css('padding-top'), 10) - parseInt(contentStart.css('padding-bottom'), 10);
+                       } else {
+                               contentStartHeight = contentStart.height();
+                       }
+                       setTimeout(function () { // workaround (setTimeout with 0 delay)
+                               contentStart
+                                       .css('height', contentStartHeight  + 'px')
+                                       .css('min-height', 'auto')
+                                       .css('width', contentStart.width() + 'px');
+                               $('#start').css('min-height', 'auto');
+                               callback();
+                       }, 0);
+               },
+
+               showChatPage: function Ui_showChatPage(serverName) {
+                       if (serverName !== undefined) {
+                               $('#chat').data('serverName', serverName);
+                       }
+                       $.mobile.changePage('#chat');
+               },
+
+               showKeyboardPage: function Ui_showKeyboardPage() {
+                       $.mobile.changePage('#keyboard');
+               },
+
+               clearChatDialog: function Ui_clearChatDialog() {
+                       $('#chat-content .ui-listview').empty();
+               },
+
+               showPowerOnButton: function Ui_showPowerOnButton() {
+                       $('#start-monit').hide();
+                       $('#serverButton').hide();
+                       $('#clientButton').hide();
+                       $('#turnOnButton').show();
+               },
+
+               showStartButtons: function Ui_showStartButtons() {
+                       $('#start-monit').hide();
+                       $('#turnOnButton').hide();
+                       $('#serverButton').show();
+                       $('#clientButton').show();
+               },
+
+               hideStartButtons: function Ui_hideStartButtons() {
+                       $('#serverButton').hide();
+                       $('#clientButton').hide();
+                       $('#turnOnButton').hide();
+                       $('#start-monit').show();
+               },
+
+               addDeviceToList: function Ui_addDeviceToList(device) {
+                       var listElement, address, sub2, ul = $('#choose-content ul.ui-listview');
+
+                       listElement = this.templateManager.get('server_row', {
+                               'deviceAddress': device.address,
+                               'deviceName': device.name
+                       });
+
+                       ul.append(listElement);
+                       ul.listview('refresh');
+               },
+
+               clearListOfServers: function Ui_clearListOfServers() {
+                       $('#choose-content ul.ui-listview').empty();
+               },
+
+               showByePopup: function Ui_showByePopup(name) {
+                       var mode = app.getApplicationMode(), message = $('#byeMessage');
+                       if (mode === 'server') {
+                               message.html('Client name "' + name + '" is unavailable.\nYour bluetooth device will be automatically restarted.');
+                       } else if (mode === 'client') {
+                               message.html('Server name "' + name + '" is unavailable.\nYour bluetooth device will be automatically restarted.');
+                       }
+                       $('#byePopup').popup('open', {'positionTo': 'window'});
+               },
+
+               hideByePopup: function Ui_hideByePopup() {
+                       $('#byePopup').popup('close');
+               },
+
+               showMessagePopup: function Ui_showMessagePopup(message) {
+                       var messagePopup = $('#messagePopup');
+                       messagePopup.find('.ui-popup-text').text(message);
+                       messagePopup.popup('open', {'positionTo': 'window'});
+               },
+
+               hideMessagePopup: function Ui_hideMessagePopup() {
+                       $('#messagePopup').popup('close');
+               },
+
+               displayReceivedMessage: function Ui_displayReceivedMessage(name, text, ping, bye) {
+                       var listElement, span, ul;
+                       text = decodeURIComponent(text);
+                       name = decodeURIComponent(name);
+                       if (bye) {
+                               this.showByePopup(name);
+                       } else if (ping) {
+                               app.setConnection(true);
+                               $('#chat-header-type').append(' - connected with ' + name);
+                               this.checkSendButtonState();
+                       } else {
+                               listElement = this.templateManager.get('left_bubble', {
+                                       'text': text
+                               });
+                               ul = $('#chat-content > .ui-scrollview-view > ul');
+                               ul.append(listElement);
+                               ul.listview('refresh');
+                       }
+               },
+
+               enableSendButton: function Ui_enableSendButton() {
+                       $('#ui-mySend')
+                               .css({'pointer-events': 'auto', 'color': '#000'})
+                               .removeClass('ui-disabled');
+               },
+
+               disableSendButton: function Ui_disableSendButton() {
+                       setTimeout( function() {
+                               $('#ui-mySend')
+                                       .css({'pointer-events': 'none', 'color': '#bbb'})
+                                       .addClass('ui-disabled');
+                               },
+                               0
+                       );
+               },
+
+               checkSendButtonState: function Ui_checkSendButtonState() {
+                       if (app.helpers.checkStringLength($('#text').val().trim()) && app.isConnection()) {
+                               this.enableSendButton();
+                       } else {
+                               this.disableSendButton();
+                       }
+               },
+
+               scrollToBottom: function Ui_scrollToBottom(element) {
+                       var bottom = element.children().first().outerHeight(true) - element.height();
+                       element.scrollview('scrollTo', 0, -Math.max(0, bottom), 0);
+               },
+
+               displaySentMessage: function Ui_displaySentMessage(message) {
+                       var listElement, span, ul, content, self = this;
+                       message = decodeURIComponent(message);
+                       listElement = this.templateManager.get('right_bubble', {
+                               'text': message
+                       });
+                       content = $('#chat-content');
+                       ul = content.find('ul');
+                       ul.append(listElement);
+                       ul.listview('refresh');
+                       this.checkSendButtonState();
+                       this.scrolltimeout = setTimeout(function () {
+                               self.scrolltimeout = null;
+                               self.scrollToBottom(content);
+                       }, 700);
+               },
+
+               setDiscoveringProgress: function Ui_setDiscoveringProgress(boolean) {
+                       $('#discovering').progress('hide', !boolean).progress('running', boolean);
+               },
+
+               fixContentHeight: function Ui_fixContentHeight() {
+                       var contentHeight = screen.availHeight - $('div[data-role="header"]').outerHeight() - $('div[data-role="footer"]').outerHeight();
+                       $('div[data-role="content"]').css('height', contentHeight);
+               }
+
+       };
+
+}());
diff --git a/project/js/app.ui.templateManager.js b/project/js/app.ui.templateManager.js
new file mode 100644 (file)
index 0000000..68c6678
--- /dev/null
@@ -0,0 +1,111 @@
+/*global tizen, $, app */
+/**
+ * @class TemplateManager
+ */
+function TemplateManager() {
+       'use strict';
+       this.init();
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       TemplateManager.prototype = {
+
+               /**
+                * Template cache
+                */
+               cache: {},
+
+               /**
+                * UI module initialisation
+                */
+               init: function init() {
+               },
+
+               /**
+                * Returns template html (from cache)
+                * @param {string} tplName
+                * @param {string} tplParams
+                */
+               get: function TemplateManager_get(tplName, tplParams) {
+                       if (this.cache[tplName] !== undefined) {
+                               return this.getCompleted(this.cache[tplName], tplParams);
+                       }
+                       return '';
+               },
+
+               /**
+                * Load templates to cache
+                * @param {string} tplNames
+                * @param {function} onSuccess
+                */
+               loadToCache: function TemplateManager_loadToCache(tplNames, onSuccess) {
+                       var self = this,
+                               cachedTemplates = 0,
+                               tplName,
+                               tplPath;
+
+                       if ($.isArray(tplNames)) {
+
+                               // for each template
+                               $.each(tplNames, function (index, fileName) {
+
+                                       // cache template html
+                                       if (self.cache[fileName] === undefined) {
+                                               tplName = [fileName, app.config.get('templateExtension')].join('');
+                                               tplPath = [app.config.get('templateDir'), tplName].join('/');
+
+                                               $.ajax({
+                                                       url: tplPath,
+                                                       cache: true,
+                                                       dataType: 'html',
+                                                       async: true,
+                                                       success: function (data) {
+                                                               // increase counter
+                                                               cachedTemplates += 1;
+
+                                                               // save to cache
+                                                               self.cache[fileName] = data;
+
+                                                               // if all templates are cached launch callback
+                                                               if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') {
+                                                                       onSuccess();
+                                                               }
+                                                       },
+                                                       error: function (jqXHR, textStatus, errorThrown) {
+                                                               console.error('templateManagerError: ' + errorThrown);
+                                                       }
+                                               });
+                                       } else {
+                                               // template is already cached
+                                               cachedTemplates += 1;
+                                               // if all templates are cached launch callback
+                                               if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') {
+                                                       onSuccess();
+                                               }
+                                       }
+                               });
+
+                       }
+               },
+
+               /**
+                * Returns template completed by specified params
+               * @param {string} tplHtml
+               * @param {string} tplParams
+                */
+               getCompleted: function TemplateManager_getCompleted(tplHtml, tplParams) {
+                       var tplParam, replaceRegExp;
+
+                       for (tplParam in tplParams) {
+                               if (tplParams.hasOwnProperty(tplParam)) {
+                                       replaceRegExp = new RegExp(['%', tplParam, '%'].join(''), 'g');
+                                       tplHtml = tplHtml.replace(replaceRegExp, tplParams[tplParam]);
+                               }
+                       }
+
+                       return tplHtml;
+               }
+       };
+
+}());
\ No newline at end of file
diff --git a/project/js/main.js b/project/js/main.js
new file mode 100644 (file)
index 0000000..1a2870e
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *      Copyright 2013  Samsung Electronics Co., Ltd
+ *
+ *      Licensed under the Flora License, Version 1.1 (the "License");
+ *      you may not use this file except in compliance with the License.
+ *      You may obtain a copy of the License at
+ *
+ *              http://floralicense.org/license/
+ *
+ *      Unless required by applicable law or agreed to in writing, software
+ *      distributed under the License is distributed on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *      See the License for the specific language governing permissions and
+ *      limitations under the License.
+ */
+
+/*global $, tizen, App */
+var app = null;
+
+(function () { // strict mode wrapper
+       'use strict';
+
+       ({
+               /**
+                * Loader init - load the App constructor
+                */
+               init: function init() {
+                       var self = this;
+                       $.getScript('js/app.js')
+                               .done(function () {
+                                       app = new App();
+                                       self.loadLibs();
+                               })
+                               .fail(this.onGetScriptError);
+               },
+
+               /**
+                * Load dependencies
+                */
+               loadLibs: function loadLibs() {
+                       var loadedLibs = 0;
+                       if ($.isArray(app.requires)) {
+                               $.each(app.requires, function (index, filename) {
+                                       $.getScript(filename)
+                                               .done(function () {
+                                                       loadedLibs += 1;
+                                                       if (loadedLibs >= app.requires.length) {
+                                                               app.init();
+                                                       }
+                                               })
+                                               .fail(this.onGetScriptError);
+                               });
+                       }
+               },
+
+               /**
+                * Handle ajax errors
+                */
+               onGetScriptError: function onGetScriptError(e, jqxhr, setting, exception) {
+                       console.error('An error occurred: ' + e.message);
+               }
+       }).init(); // run the loader
+}());
diff --git a/project/templates/bye_popup.tpl b/project/templates/bye_popup.tpl
new file mode 100644 (file)
index 0000000..69bc1bf
--- /dev/null
@@ -0,0 +1,6 @@
+<div id="byePopup" data-role="popup" class="center_basic_2btn">
+       <div class="ui-popup-text" id="byeMessage"></div>
+       <div class="ui-popup-button-bg">
+               <a data-role="button" data-inline="true" id="byeOK">Ok</a>
+       </div>
+</div>
diff --git a/project/templates/chat_page.tpl b/project/templates/chat_page.tpl
new file mode 100644 (file)
index 0000000..57ae3aa
--- /dev/null
@@ -0,0 +1,20 @@
+<div id="chat" data-role="page" data-footer-exist="true">
+       <div id="chat-header" data-role="header" data-position="fixed">
+               <h1><span id="chat-header-type"></span><span id="chat-header-name"></span></h1>
+       </div>
+
+       <div id="chat-content" data-role="content">
+               <ul data-role="listview"></ul>
+       </div>
+
+       <div id="chat-footer" data-role="footer" data-position="fixed">
+               <div id="ui-textArea">
+                       <div id="ui-textArea-text">
+                               <textarea id="text" placeholder="Your message" data-role="none"></textarea>
+                       </div>
+                       <div id="ui-textArea-button">
+                               <a data-role="button" id="ui-mySend">Send</a>
+                       </div>
+               </div>
+       </div>
+</div>
\ No newline at end of file
diff --git a/project/templates/choose_page.tpl b/project/templates/choose_page.tpl
new file mode 100644 (file)
index 0000000..102d358
--- /dev/null
@@ -0,0 +1,10 @@
+<div data-role="page" id="choose">
+       <div data-role="header" id="choose-header" data-position="fixed">
+               <h1>Choose your server</h1>
+               <div data-role="progress" data-style="circle" id="discovering"></div>
+       </div>
+
+       <div data-role="content" id="choose-content">
+               <ul data-role="listview"></ul>
+       </div>
+</div>
\ No newline at end of file
diff --git a/project/templates/keyboard_page.tpl b/project/templates/keyboard_page.tpl
new file mode 100644 (file)
index 0000000..1722089
--- /dev/null
@@ -0,0 +1,16 @@
+<div data-role="page" id="keyboard">
+       <div data-role="header" id="keyboard-header" data-position="fixed">
+               <h1></h1>
+       </div>
+
+       <div data-role="content" id="keyboard-content">
+               <input type="text" id="keyboard-text" maxlength="20"/>
+       </div>
+       <div data-role="footer" data-position="fixed">
+               <div data-role="tabbar" data-style="tabbar">
+                       <ul>
+                               <li id="keyboard-ok-button"><a href="#">OK</a></li>
+                       </ul>
+               </div>
+       </div>
+</div>
\ No newline at end of file
diff --git a/project/templates/left_bubble.tpl b/project/templates/left_bubble.tpl
new file mode 100644 (file)
index 0000000..2d20b1b
--- /dev/null
@@ -0,0 +1,3 @@
+<li class="ui-li-bubble-left">
+       %text%
+</li>
\ No newline at end of file
diff --git a/project/templates/message_popup.tpl b/project/templates/message_popup.tpl
new file mode 100644 (file)
index 0000000..d69aafd
--- /dev/null
@@ -0,0 +1,6 @@
+<div id="messagePopup" data-role="popup" class="center_basic_2btn">
+       <div class="ui-popup-text"></div>
+       <div class="ui-popup-button-bg">
+               <a data-role="button" data-inline="true" id="messageOK">OK</a>
+       </div>
+</div>
diff --git a/project/templates/right_bubble.tpl b/project/templates/right_bubble.tpl
new file mode 100644 (file)
index 0000000..507e30f
--- /dev/null
@@ -0,0 +1,3 @@
+<li class="ui-li-bubble-right">
+       %text%
+</li>
\ No newline at end of file
diff --git a/project/templates/server_row.tpl b/project/templates/server_row.tpl
new file mode 100644 (file)
index 0000000..7780cc4
--- /dev/null
@@ -0,0 +1,7 @@
+<li class="ui-li-has-multiline" address="%deviceAddress%" name="%deviceName%">
+       <a href="#">
+               <div class="server-row-name">%deviceName%</div>
+               <span class="ui-li-text-sub">%deviceAddress%</span>
+               <span class="ui-li-text-sub2"></span>
+       </a>
+</li>
\ No newline at end of file
diff --git a/tizen-app-template.xml b/tizen-app-template.xml
new file mode 100755 (executable)
index 0000000..9bad27d
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<tizen-app-template xmlns="http://www.tizen.org/tizen-app-template" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" template-version="" sdk-version="" icon32="tizen_32.png" icon64="tizen_64.png" xsi:schemaLocation="http://www.tizen.org/tizen-app-template tizen-app-template.xsd ">
+    <template-name>BluetoothChat</template-name>
+    <widget-type>TIZEN</widget-type>
+    <build-property key="usedLibraryType" value="WebUIFramework"/>
+    <description-file-name>description.xml</description-file-name>
+    <options>
+        <supportLibraries>
+          <library name="Tizen Web UI Framework"/>
+        </supportLibraries>
+    </options>
+</tizen-app-template>
diff --git a/tizen_32.png b/tizen_32.png
new file mode 100644 (file)
index 0000000..61f35c0
Binary files /dev/null and b/tizen_32.png differ
diff --git a/tizen_64.png b/tizen_64.png
new file mode 100644 (file)
index 0000000..b188083
Binary files /dev/null and b/tizen_64.png differ