Moving project code to new repo - first commit.
authorsensortag <j.honsi@ti.com>
Wed, 10 Sep 2014 17:35:19 +0000 (13:35 -0400)
committersensortag <j.honsi@ti.com>
Wed, 10 Sep 2014 17:35:19 +0000 (13:35 -0400)
108 files changed:
.classpath [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.project [new file with mode: 0644]
AndroidManifest.xml [new file with mode: 0644]
assets/SensorTagImgA.bin [new file with mode: 0644]
assets/SensorTagImgB.bin [new file with mode: 0644]
assets/about.css [new file with mode: 0644]
assets/about.html [new file with mode: 0644]
assets/help.css [new file with mode: 0644]
assets/help_device.html [new file with mode: 0644]
assets/help_scan.html [new file with mode: 0644]
assets/license.css [new file with mode: 0644]
assets/license.html [new file with mode: 0644]
libs/android-support-v4.jar [new file with mode: 0644]
project.properties [new file with mode: 0644]
res/drawable-hdpi/bluetooth.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_about.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_bluetooth.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_cancel.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_refresh.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_settings.png [new file with mode: 0644]
res/drawable-hdpi/list_item_normal.xml [new file with mode: 0644]
res/drawable-hdpi/tible.png [new file with mode: 0644]
res/drawable-mdpi/buttonsoffoff.png [new file with mode: 0644]
res/drawable-mdpi/buttonsoffon.png [new file with mode: 0644]
res/drawable-mdpi/buttonsonoff.png [new file with mode: 0644]
res/drawable-mdpi/buttonsonon.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_about.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_bluetooth.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_cancel.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_refresh.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_settings.png [new file with mode: 0644]
res/drawable-mdpi/reed_closed.png [new file with mode: 0644]
res/drawable-mdpi/reed_open.png [new file with mode: 0644]
res/drawable-mdpi/ti_stk_2c_pos_rgb_png.png [new file with mode: 0644]
res/drawable-mdpi/tible.png [new file with mode: 0644]
res/drawable-xhdpi/accelerometer.png [new file with mode: 0644]
res/drawable-xhdpi/barometer.png [new file with mode: 0644]
res/drawable-xhdpi/gyroscope.png [new file with mode: 0644]
res/drawable-xhdpi/humidity.png [new file with mode: 0644]
res/drawable-xhdpi/ic_action_about.png [new file with mode: 0644]
res/drawable-xhdpi/ic_action_bluetooth.png [new file with mode: 0644]
res/drawable-xhdpi/ic_action_cancel.png [new file with mode: 0644]
res/drawable-xhdpi/ic_action_refresh.png [new file with mode: 0644]
res/drawable-xhdpi/ic_action_settings.png [new file with mode: 0644]
res/drawable-xhdpi/irtemperature.png [new file with mode: 0644]
res/drawable-xhdpi/lightsensor.png [new file with mode: 0644]
res/drawable-xhdpi/reedrelay.png [new file with mode: 0644]
res/drawable-xhdpi/sensortag.png [new file with mode: 0644]
res/drawable-xhdpi/sensortag_magnetometer.png [new file with mode: 0644]
res/drawable-xhdpi/sensortag_simplekeys.png [new file with mode: 0644]
res/drawable-xhdpi/st2.png [new file with mode: 0644]
res/drawable-xhdpi/temperature.png [new file with mode: 0644]
res/drawable-xhdpi/tible.png [new file with mode: 0644]
res/drawable-xhdpi/unknown.png [new file with mode: 0644]
res/drawable-xxhdpi/ic_action_about.png [new file with mode: 0644]
res/drawable-xxhdpi/ic_action_bluetooth.png [new file with mode: 0644]
res/drawable-xxhdpi/ic_action_cancel.png [new file with mode: 0644]
res/drawable-xxhdpi/ic_action_refresh.png [new file with mode: 0644]
res/drawable-xxhdpi/ic_action_settings.png [new file with mode: 0644]
res/layout/activity_file.xml [new file with mode: 0644]
res/layout/activity_fwupdate.xml [new file with mode: 0644]
res/layout/dialog_about.xml [new file with mode: 0644]
res/layout/dialog_license.xml [new file with mode: 0644]
res/layout/element_characteristic.xml [new file with mode: 0644]
res/layout/element_device.xml [new file with mode: 0644]
res/layout/element_file.xml [new file with mode: 0644]
res/layout/fragment_help.xml [new file with mode: 0644]
res/layout/fragment_pager.xml [new file with mode: 0644]
res/layout/fragment_scan.xml [new file with mode: 0644]
res/layout/frame_progress.xml [new file with mode: 0644]
res/layout/services_browser.xml [new file with mode: 0644]
res/layout/services_browser2.xml [new file with mode: 0644]
res/menu/device_activity_actions.xml [new file with mode: 0644]
res/menu/main_activity_actions.xml [new file with mode: 0644]
res/values/strings.xml [new file with mode: 0644]
res/values/styles.xml [new file with mode: 0644]
res/xml/gatt_uuid.xml [new file with mode: 0644]
res/xml/list_gradient.xml [new file with mode: 0644]
res/xml/popup.xml [new file with mode: 0644]
res/xml/preferences.xml [new file with mode: 0644]
res/xml/preferences2.xml [new file with mode: 0644]
src/com/example/ti/ble/common/BleDeviceInfo.java [new file with mode: 0644]
src/com/example/ti/ble/common/BluetoothLeService.java [new file with mode: 0644]
src/com/example/ti/ble/common/GattInfo.java [new file with mode: 0644]
src/com/example/ti/ble/common/HelpView.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/AboutDialog.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/BarometerCalibrationCoefficients.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/DeviceActivity.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/DeviceView.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/FileActivity.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/FwUpdateActivity.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/LicenseDialog.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/MagnetometerCalibrationCoefficients.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/MainActivity.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/PreferencesActivity.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/PreferencesFragment.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/PreferencesListener.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/ScanView.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/Sensor.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/SensorTagGatt.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/SimpleKeysStatus.java [new file with mode: 0644]
src/com/example/ti/ble/sensortag/ViewPagerActivity.java [new file with mode: 0644]
src/com/example/ti/util/Conversion.java [new file with mode: 0644]
src/com/example/ti/util/CustomTimer.java [new file with mode: 0644]
src/com/example/ti/util/CustomTimerCallback.java [new file with mode: 0644]
src/com/example/ti/util/CustomToast.java [new file with mode: 0644]
src/com/example/ti/util/Point3D.java [new file with mode: 0644]

diff --git a/.classpath b/.classpath
new file mode 100644 (file)
index 0000000..b76ec6c
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
+       <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
+       <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="src" path="gen"/>\r
+       <classpathentry kind="output" path="bin/classes"/>\r
+</classpath>\r
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5228a85
--- /dev/null
@@ -0,0 +1,27 @@
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.rar
+*.tar
+*.zip
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+.hg
+.hgignore
+.hgtags
+._*
+.Spotlight-V100
+.Trashes
+Icon?
+ehthumbs.db
+Thumbs.db
+bin*
+tmp
diff --git a/.project b/.project
new file mode 100644 (file)
index 0000000..bc25a77
--- /dev/null
+++ b/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>BleSensorTag</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..9493444
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"\r
+    package="com.example.ti.ble.sensortag"\r
+    android:versionCode="2"\r
+    android:versionName="1.01" >\r
+\r
+    <uses-permission android:name="android.permission.BLUETOOTH" />\r
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />\r
+    <uses-permission android:name="android.permission.INTERNET" />\r
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />\r
+    \r
+    <uses-sdk\r
+        android:minSdkVersion="18"\r
+        android:targetSdkVersion="19" />\r
+    \r
+    <uses-feature\r
+        android:name="android.hardware.bluetooth_le"\r
+        android:required="true" />\r
+\r
+    <application\r
+        android:allowBackup="false"\r
+        android:icon="@drawable/tible"\r
+        android:label="@string/app_name" \r
+        android:theme="@android:style/Theme.Holo.Light" >\r
+        <service\r
+            android:name="com.example.ti.ble.common.BluetoothLeService"\r
+            android:enabled="true" />\r
+\r
+        <activity\r
+            android:name="com.example.ti.ble.sensortag.MainActivity"\r
+            android:label="@string/app_name"\r
+            android:screenOrientation="portrait" >\r
+            <intent-filter>\r
+                <action android:name="android.intent.action.MAIN" />\r
+\r
+                <category android:name="android.intent.category.DEFAULT" />\r
+                <category android:name="android.intent.category.LAUNCHER" />\r
+            </intent-filter>\r
+        </activity>\r
+        <activity\r
+            android:name="com.example.ti.ble.sensortag.DeviceActivity"\r
+            android:parentActivityName="MainActivity"\r
+            android:screenOrientation="portrait" />\r
+        <activity\r
+            android:name="com.example.ti.ble.sensortag.ServiceActivity"\r
+            android:parentActivityName="DeviceActivity"\r
+            android:screenOrientation="portrait" />\r
+        <activity\r
+            android:name="com.example.ti.ble.sensortag.FwUpdateActivity"\r
+            android:parentActivityName="DeviceActivity"\r
+            android:screenOrientation="portrait" />\r
+        <activity\r
+            android:name="com.example.ti.ble.sensortag.FileActivity"\r
+            android:parentActivityName="FwUpdateActivity"\r
+            android:screenOrientation="portrait" />\r
+        <activity\r
+            android:name="com.example.ti.ble.sensortag.PreferencesActivity"\r
+            android:parentActivityName="DeviceActivity"\r
+            android:screenOrientation="portrait"\r
+            android:label="Preferences"/>\r
+        \r
+    </application>\r
+\r
+\r
+</manifest>\r
diff --git a/assets/SensorTagImgA.bin b/assets/SensorTagImgA.bin
new file mode 100644 (file)
index 0000000..dc731f0
Binary files /dev/null and b/assets/SensorTagImgA.bin differ
diff --git a/assets/SensorTagImgB.bin b/assets/SensorTagImgB.bin
new file mode 100644 (file)
index 0000000..9eef0ec
Binary files /dev/null and b/assets/SensorTagImgB.bin differ
diff --git a/assets/about.css b/assets/about.css
new file mode 100644 (file)
index 0000000..4f72254
--- /dev/null
@@ -0,0 +1,39 @@
+/* ------------------------------------------------------------\r
+ *\r
+ * File        : about.css\r
+ *\r
+ * Description : Styles for About Dialog\r
+ *\r
+ * ----------------------------------------------------------- */\r
+body \r
+{\r
+padding:0;\r
+background-color:white;\r
+}\r
+\r
+div.main \r
+{\r
+margin:0 auto;\r
+padding:0;\r
+color:black;\r
+text-align:justify;\r
+}\r
+\r
+p\r
+{\r
+font-size:16px;\r
+}\r
+\r
+p.info\r
+{\r
+text-align:center;\r
+color:red;\r
+}\r
+\r
+p.copy\r
+{\r
+text-align:center;\r
+color:red;\r
+}\r
+\r
+\r
diff --git a/assets/about.html b/assets/about.html
new file mode 100644 (file)
index 0000000..eaeba26
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"\r
+    "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />\r
+<meta name="Author" content="Texas Instruments" />\r
+<title>About BLE SensorTag</title>\r
+<link rel="stylesheet" type="text/css" href="about.css" />\r
+</head>\r
+<body>\r
+  <div class="main">\r
+    <p><b>BLE SensorTag application</b> from <b>Texas Instruments</b> displays converted values from each of the six sensors\r
+    in the SensorTag. It also visualizes button presses. Up to four sensors may be used simultaneously (including keys).</p><hr />\r
+    <p class="copy">&copy; 2013-2014 Texas Instruments</p>\r
+   </div>\r
+</body>\r
+</html>\r
diff --git a/assets/help.css b/assets/help.css
new file mode 100644 (file)
index 0000000..618cfb0
--- /dev/null
@@ -0,0 +1,54 @@
+/* ------------------------------------------------------------\r
+ *\r
+ * File        : help.css\r
+ *\r
+ * Description : Styles for the BLE Device Monitor Help pages\r
+ *\r
+ * ----------------------------------------------------------- */\r
+body \r
+{\r
+       background-color:#eee; \r
+       padding:0;\r
+       color:black;\r
+}\r
+\r
+h1 \r
+{\r
+       font-size:20px;\r
+       text-align:center;\r
+}\r
+\r
+h2\r
+{\r
+       font-size:18px;\r
+       text-align:center;\r
+}\r
+\r
+div.main \r
+{\r
+       margin:0 auto;\r
+       text-align:justify;\r
+}\r
+\r
+p\r
+{\r
+       font-size:16px;\r
+}\r
+\r
+p.info\r
+{\r
+       text-align:center;\r
+       color:red;\r
+}\r
+\r
+p.copy\r
+{\r
+       text-align:center;\r
+       color:red;\r
+}\r
+\r
+b\r
+{\r
+       color:#003;\r
+}\r
+\r
diff --git a/assets/help_device.html b/assets/help_device.html
new file mode 100644 (file)
index 0000000..5df5156
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<!-- *********************************************************\r
+**   File    : help_device.html\r
+**   Descr.  : Help for device view\r
+**** ****************************************************** -->\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />\r
+<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache" />\r
+<meta HTTP-EQUIV="expires" CONTENT="0">\r
+<meta name="Author" content="Texas Instruments" />\r
+<title>BLE Device Monitor</title>\r
+<link rel="stylesheet" type="text/css" href="help.css">\r
+</head>\r
+\r
+<body>\r
+       <div class="main">\r
+               <h1>Sensor View Help</h1>\r
+               <p>When the view is started a <b>Service Discovery</b> is initiated. On <b>Service Discovery</b> completion (may take a few seconds),\r
+               sensor images appear and data is displayed next to them. The <b>Preferences</b> tab in the options menu can be used to select <i>which</i> sensors\r
+               to show. Note that a maximum of four sensors may be activated per connection instance due to a limitation in Android's Bluetooth low energy stack on the number of \r
+               notifications.</p>\r
+               <p>Note that magnetometer, gyroscope and height measurement (barometer) are calibrated by tapping on the respective entry in the sensor list. The measured height shown\r
+               is calculated based on the difference in air pressure between the current measurement and the pressure at the moment of calibration. Measurements are always calibrated\r
+               on connection (but may be re-calibrated any time).</p>\r
+               <p>The SensorTag firmware can be upgraded OTA (Over The Air) via <b>Firmware Update</b> in the Options Menu. The application will contain images for the latest firmware, \r
+               but it is also possible to download custom images from Android's 'Download' directory. There are \r
+               two FW images for each FW revision. These are labeled <q>A</q> and <q>B</q> and differ only by the destination address in the \r
+               SensorTag flash. Alternative images must always be used; if the current image in flash is of type <q>A</q> the new one must of type \r
+               <q>B</q> and vice versa.<hr />\r
+    <p class="copy">&copy; 2013-2014 Texas Instruments</p>\r
+  </div>\r
+</body>\r
+</html>\r
+\r
diff --git a/assets/help_scan.html b/assets/help_scan.html
new file mode 100644 (file)
index 0000000..0c678b2
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<!-- **********************************************************\r
+**   File    : help_scan.html\r
+**   Descr.  : Help view for scan activity\r
+**** ****************************************************** -->\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r
+<meta HTTP-EQUIV="Pragma" CONTENT="no-cache">\r
+<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache">\r
+<meta HTTP-EQUIV="expires" CONTENT="0">\r
+<meta name="Author" content="Texas Instruments">\r
+<title>BLE SensorTag</title>\r
+<link rel=stylesheet type="text/css" href="help.css">\r
+</head>\r
+\r
+<body>\r
+       <div class="main">\r
+         <h1>Scan View Help</h1>\r
+               <p>Provided that the <b>Bluetooth Adapter</b> is available and turned on and Bluetooth low energy supported on the device \r
+               (the application will request to turn the adapter on if detected off at start-up), the <b>BLE SensorTag App</b> \r
+         will start device discovery (scanning) automatically. Scanning will stop when any of the following conditions is met:</p>\r
+         <ul>\r
+         <li><b>Stop</b> button tapped</b>\r
+         <li>A <b>device</b> in the list tapped</li>\r
+         <li><b>Ten seconds</b> elapsed since scanning started</li>\r
+         </ul>\r
+               <p>Scanning can be restarted any time by tapping the <b>Scan</b> button. During scanning Received Signal Strength Indicator (RSSI) values are continuously updated. Note that\r
+               some devices do not provide continuous scan results (Nexus 4, Nexus 7 2013), on these devices the RSSI value will appear only once. \r
+               When a device in the list is selected by the user, the application will attempt to connect to it. If the connection succeeds, \r
+               the <u>Device View</u> will be launched, and this is where data from the enabled sensors are displayed. If connection times out an error message\r
+               is displayed. This will happen when the SensorTag doesn't advertise, so always make sure it is advertising by pushing the side button on the SensorTag\r
+               (this button toggles advertising).</p>\r
+               <p>The options menu gives direct access to the SensorTag web page, and to TI's e2e forum. The Bluetooth settings dialog can also\r
+               be accessed from here. There is also a brief About dialog with information about the SensorTag, the Android device name and the Android build.\r
+               </p>\r
+    <p class="copy"<hr>&copy; 2013-2014 Texas Instruments</p>\r
+</div>\r
+\r
+</body>\r
+</html>\r
+\r
diff --git a/assets/license.css b/assets/license.css
new file mode 100644 (file)
index 0000000..640ab31
--- /dev/null
@@ -0,0 +1,37 @@
+/* ------------------------------------------------------------\r
+ *\r
+ * File        : license.css\r
+ *\r
+ * Description : Styles for License Dialog\r
+ *\r
+ * ----------------------------------------------------------- */\r
+body \r
+{\r
+       padding:0;\r
+       background-color:white;\r
+}\r
+\r
+div.main \r
+{\r
+       margin:0 auto;\r
+       padding:0;\r
+       color:black;\r
+       text-align:justify;\r
+}\r
+\r
+h2\r
+{\r
+       font-size:16px;\r
+       color:red;\r
+}\r
+\r
+h2\r
+{\r
+       font-size:15px;\r
+}\r
+\r
+p\r
+{\r
+       font-size:14px;\r
+}\r
+\r
diff --git a/assets/license.html b/assets/license.html
new file mode 100644 (file)
index 0000000..f7f2f41
--- /dev/null
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<!-- **********************************************************\r
+**   File    : license.html\r
+**   Descr.  : Content of License Dialog\r
+**** ****************************************************** -->\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r
+<meta HTTP-EQUIV="Pragma" CONTENT="no-cache">\r
+<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache">\r
+<meta HTTP-EQUIV="expires" CONTENT="0">\r
+<meta name="Author" content="Texas Instruments">\r
+<title>License</title>\r
+<link rel=stylesheet type="text/css" href="license.css">\r
+</head>\r
+\r
+<body>\r
+       <div class="main">\r
+               <h2>TEXAS INSTRUMENTS INCORPORATED PRIVACY POLICY</h2>\r
+               This application, and your use of this application, is subject to <b>TI’s Privacy Policy</b> available at <a href="http://www.ti.com/corp/docs/legal/privacy.shtml">http://www.ti.com/corp/docs/legal/privacy.shtml</a>. By downloading, installing, copying, or otherwise using this application, you consent to the use of your information as described above and as described in TI’s Privacy Policy.</p>\r
+               <h2>TEXAS INSTRUMENTS INCORPORATED LICENSED APPLICATION END USER LICENSE AGREEMENT</h2>\r
+               <p>You understand and agree that the <b>Licensed Application</b> is not recommended for consumer use, but is intended and targeted for applications developers’ use.  You also understand and agree that the Licensed Application processes and displays any data that the user feeds into TI sensors with which the Licensed Application is designed to communicate.  The Licensed Application is for demonstration and development purposes only; it is not for diagnostic or therapeutic use.</p>\r
+               <p>\r
+               This Licensed Application End User License Agreement (this “<u>Agreement</u>”) is a legal agreement between you and Texas Instruments Incorporated (“<u>TI</u>”). In this Agreement “You” means you personally if you will exercise the rights granted for your own benefit, but it means your company (or you on behalf of your company) if you will exercise the rights granted for your company’s benefit. The “<u>Licensed Application</u>” subject to this Agreement includes the software programs and any associated electronic documentation (in each case, in whole or in part) that accompany this Agreement and that you access online, as well as any updates to such software programs and documentation, if any, provided to you at TI’s sole discretion. By downloading, installing, copying, or otherwise using the Licensed Application you agree to abide by the provisions set forth herein. This Agreement is made available to or displayed for you to read prior to downloading, installing, or otherwise using the Licensed Application.  If you choose not to accept or agree with these provisions, do not download, install, or use the Licensed Application.\r
+               </p>\r
+               <h3>a. Scope of license</h3>\r
+               <p>\r
+               i. This license granted to You for the Licensed Application by TI is limited to a non-transferable license to use the Licensed Application on a mobile device that You control, and, if applicable, as permitted by usage rules pertaining to the mobile operating system on which you download the Licensed Application (e.g., Android) (“Usage Rules”). This license does not allow You to use the Licensed Application on any mobile device that You do not own or control, and You may not distribute or make the Licensed Application available over a network where it could be used by multiple mobile devices at the same time. You may not rent, lease, lend, sell, redistribute or sublicense the Licensed Application. You will not, and will not permit any person or entity to, copy (except as expressly permitted by this license and the Usage Rules), decompile, reverse engineer, disassemble, attempt to derive the source code of, modify, or create derivative works of the Licensed Application, any updates, or any part thereof (except as and only to the extent any foregoing restriction is prohibited by applicable law or to the extent as may be permitted by the licensing terms governing use of any Open Source Software (defined below) included with the Licensed Application). You may use the Licensed Application with Open Source Software or with software developed using Open Source Software tools provided you do not incorporate, combine or distribute the Licensed Application in a manner that subjects the Licensed Application to any license obligations or any other intellectual property related terms of any license governing such Open Source Software. You will not remove, alter, cover, or obscure any confidentiality, trade secret, trade mark, patent, copyright or other proprietary notice or other identifying marks or designs from any component of the Licensed Application. Any attempt to do so is a violation of the rights of TI and its licensors. If You breach this restriction, You may be subject to prosecution and damages. The terms of the license will govern any upgrades provided by TI that replace and/or supplement the original product, unless such upgrade is accompanied by a separate license in which case the terms of that license will govern.\r
+               </p>\r
+               <p>ii.  The Licensed Application may be bundled with software and associated electronic documentation, if any, licensed under terms other than the terms of this Agreement (in whole or in part, “Other Licensed Materials”), including, for example Open Source Software and/or TI-owned or third party Proprietary Software licensed under such other terms.  “Open Source Software” means any software licensed under terms requiring that (A) other software (“Proprietary Software”) incorporated, combined, or distributed with such software or developed using such software: (i) be disclosed or distributed in source code form; or (ii) otherwise be licensed on terms inconsistent with the terms of this Agreement, including but not limited to permitting use of the Proprietary Software on or with applications other than the Licensed Application, or (B) the owner of Proprietary Software to license any of its patents to users of the Open Source Software and/or Proprietary Software incorporated, combined, or distributed with such Open Source Software or developed using such Open Source Software\r
+</p>           \r
+<p>\r
+iii.   If by accepting this Agreement, you gain access to Other Licensed Materials, they will be listed in the applicable software manifest. Your use of the Other Licensed Materials is subject to the applicable other licensing terms acknowledgements and disclaimers as specified in the applicable software manifest and/or identified or included with the Other Licensed Materials in the software bundle.  For clarification, this Agreement does not limit your rights under, or grant you rights that supersede, the terms of any applicable Other Licensed Materials license agreement. If any of the Other Licensed Materials is Open Source Software that has been provided to you in object code only under terms that obligate TI to provide to you or show you where you can access the source code versions of such Open Source Software, TI will provide to you, or show you where you can access, such source code if you contact TI at Texas Instruments Incorporated, 12500 TI Boulevard, Mail Station 8725, Dallas, Texas 75243, Attention: Open Source Review Board. In the event you choose not to accept or agree with the terms in any applicable Other Licensed Materials license agreement, you must terminate this Agreement.\r
+</p>\r
+\r
+<p>iv. If the Licensed Application is designed to be used with a TI evaluation module for demonstration purposes, neither the Licensed Application nor the TI evaluation module may be used for diagnosing, curing, treating, mitigating, preventing diseases and health conditions, or for therapeutic purposes, and may only be used for research and development purposes. \r
+</p>\r
+\r
+<p>\r
+v.     You understand and agree that the Licensed Application is not recommended for consumer use, but is intended and targeted for applications developers’ use.  You also understand and agree that the Licensed Application processes and displays any data that the user feeds into TI sensors with which the Licensed Application is designed to communicate.  This application is for demonstration and development purposes only; it is not for diagnostic or therapeutic use.\r
+</p>\r
+\r
+<h3>b. Ownership</h3>\r
+<p>\r
+The Licensed Application is licensed, not sold to you, and can only be used in accordance with the terms of this Agreement.  Subject to the license granted to you pursuant to this Agreement, TI and its licensors own and shall continue to own all right, title and interest in and to the Licensed Application, including all copies thereof.  You agree that all fixes, modifications, and improvements to the Licensed Application conceived of or made by TI that are based, either in whole or in part, on your feedback, suggestions, or recommendations are the exclusive property of TI and all right, title, and interest in and to such fixes, modifications or improvements to the Licensed Application will vest solely in TI. Moreover, you acknowledge and agree that when your independently developed software or hardware components are combined, in whole or in part, with the Licensed Application, your right to use the combined work that includes the Licensed Application remains subject to the terms and conditions of this Agreement.\r
+</p>\r
+\r
+<h3>c. Consent to Use of Data</h3>\r
+<p>\r
+You agree that TI may collect and use technical data and related information, including but not limited to technical information about Your device, system and application software, and peripherals, that is gathered periodically to facilitate the provision of software updates, product support and other services to You (if any) related to the Licensed Application. TI may use this information, as long as it is in a form that does not personally identify You, to improve its products or to provide services or technologies to You. The Licensed Application, and your use of the Licensed Application, is subject to TI’s Privacy Policy available at <a href="http://www.ti.com/corp/docs/legal/privacy.shtml">http://www.ti.com/corp/docs/legal/privacy.shtml</a>. By downloading, installing, copying, or otherwise using the Licensed Application, you consent to the use of your information as described above and as described in TI’s Privacy Policy.\r
+</p>\r
+\r
+<h3>d. Termination.</h3><p>The license is effective until terminated by You or TI. Your rights under this license will terminate automatically without notice from TI if You fail to comply with any term(s) of this Agreement. Upon termination of this Agreement, You shall cease all use of the Licensed Application, and destroy all copies, full or partial, of the Licensed Application.</p>\r
+\r
+<h3>e. Accessed Services; Third Party Materials.</h3><p>The Licensed Application may enable access to TI’s and third party services and web sites (collectively and individually, “Accessed Services”). Use of the Accessed Services may require internet access and You accept additional terms of service for the Accessed Services, and may also be subject to other privacy practices and policies.</p>\r
+<p>TI does not warrant or endorse and does not assume and will not have any liability or responsibility to You or any other person for any third-party content, data, information, applications, or materials from third parties (“Third Party Materials”), Accessed Services, web sites, or for any other materials, products, or services of third parties. Third Party Materials and links to other web sites are provided solely as a convenience to You. Neither TI, nor any of its content providers, guarantees the availability, accuracy, completeness, reliability, or timeliness of any information displayed by any Accessed Services. You agree to use the Accessed Services at Your sole risk and that TI shall not have any liability to You for content that may be found to be offensive, indecent, or objectionable.</p>\r
+<p>Third party Accessed Services and Third Party Materials that may be accessed from, displayed on or linked to from a mobile device are not available in all languages or in all countries. TI makes no representation that such Accessed Services and Third Party Materials are appropriate or available for use in any particular location. To the extent You choose to access such Accessed Services or Third Party Materials, You do so at Your own initiative and are responsible for compliance with any applicable laws. TI, and its licensors, reserve the right to change, suspend, remove, or disable access to any Accessed Services at any time without notice. In no event will TI be liable for the removal of or disabling of access to any such Accessed Services. TI may also impose limits on the use of or access to certain Accessed Services without notice or liability.</p>\r
+\r
+<h3>f. Intellectual Property Rights.</h3><p>The Licensed Application contains copyrighted material, trade secrets, and other proprietary information of TI and its licensors that are protected by copyright laws, international copyright treaties, and trade secret laws, as well as other intellectual property laws. To protect TI’s and its licensors’ rights in the Licensed Application, you agree to the restrictions contained in Section (a) above.</p>\r
+\r
+<h3>g. No Other License.</h3><p>TI reserves all rights not specifically granted under this Agreement. Nothing in this Agreement shall be construed as a license to any intellectual property rights of TI other than those rights embodied in the Licensed Application provided to you by TI.  EXCEPT AS PROVIDED HEREIN, NO OTHER LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, TO ANY OTHER TI INTELLECTUAL PROPERTY RIGHTS IS GRANTED HEREIN.</p>\r
+\r
+<h3>h. Covenant not to Sue.</h3><p>During the term of this Agreement, you agree not to assert a claim against TI or its licensees that the Licensed Application infringes your intellectual property rights.</p>\r
+\r
+<h3>i. NO WARRANTY:</h3><p>YOU EXPRESSLY ACKNOWLEDGE AND AGREE THAT USE OF THE LICENSED APPLICATION IS AT YOUR SOLE RISK AND THAT THE ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY AND EFFORT IS WITH YOU. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED APPLICATION AND ANY SERVICES PERFORMED OR PROVIDED BY THE LICENSED APPLICATION ("SERVICES") ARE PROVIDED "AS IS" AND “AS AVAILABLE”, WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, AND TI HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS WITH RESPECT TO THE LICENSED APPLICATION AND ANY SERVICES, EITHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NON-INFRINGEMENT OF ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADE SECRETS, OR OTHER INTELLECTUAL PROPERTY RIGHTS. TI DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE LICENSED APPLICATION, THAT THE FUNCTIONS CONTAINED IN, OR SERVICES PERFORMED OR PROVIDED BY, THE LICENSED APPLICATION WILL MEET YOUR REQUIREMENTS, THAT THE OPERATION OF THE LICENSED APPLICATION OR SERVICES WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE LICENSED APPLICATION OR SERVICES WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY TI OR ITS AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SHOULD THE LICENSED APPLICATION OR SERVICES PROVE DEFECTIVE, YOU ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES OR LIMITATIONS ON APPLICABLE STATUTORY RIGHTS OF A CONSUMER, SO THE ABOVE EXCLUSION AND LIMITATIONS MAY NOT APPLY TO YOU.</p>\r
+<p> FURTHERMORE, YOU ACKNOWLEDGE AND AGREE THAT THE LICENSED APPLICATION HAS NOT BEEN TESTED OR CERTIFIED BY ANY GOVERNMENT AGENCY OR INDUSTRY REGULATORY ORGANIZATION OR ANY OTHER THIRD PARTY ORGANIZATION.</p>\r
+<p>\r
+YOU AGREE TO USE YOUR INDEPENDENT JUDGMENT IN DEVELOPING YOUR PRODUCTS. NOTHING CONTAINED IN THIS AGREEMENT WILL BE CONSTRUED AS A WARRANTY OR REPRESENTATION BY TI TO MAINTAIN PRODUCTION OF ANY TI SEMICONDUCTOR DEVICE OR OTHER HARDWARE OR SOFTWARE WITH WHICH THE LICENSED APPLICATION MAY BE USED.</p> \r
+\r
+<h3>j. LIMITATION OF LIABILITY.</h3><p>TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT SHALL TI OR ITS LICENSORS BE LIABLE FOR PERSONAL INJURY, OR ANY INCIDENTAL, SPECIAL, INDIRECT, INCIDENTIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES WHATSOEVER, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, COST OF REMOVAL OR REINSTALLATION, OUTSIDE COMPUTER TIME, LABOR COSTS, LOSS OF DATA, LOSS OF GOODWILL, LOSS OF SAVINGS, LOSS OF USE OR INTERRUPTION OF BUSINESS, OR ANY OTHER DAMAGES OR LOSSES, ARISING OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE THE LICENSED APPLICATION, HOWEVER CAUSED, REGARDLESS OF THE THEORY OF LIABILITY (CONTRACT, TORT, OR OTHERWISE) AND EVEN IF TI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event shall TI’s or its licensors’ aggregate liability under this Agreement or arising out of your use of the Licensed Application total liability to you for all damages exceed the amount of fifty dollars ($50.00). The foregoing limitations will apply even if the above stated remedy fails of its essential purpose.</p>\r
+\r
+<h3>k. Indemnification Disclaimer.</h3><p>YOU ACKNOWLEDGE AND AGREE THAT TI SHALL NOT BE LIABLE FOR AND SHALL NOT DEFEND OR INDEMNIFY YOU AGAINST ANY THIRD PARTY CLAIM THAT RELATES TO OR IS BASED ON YOUR USE OF THE LICENSED APPLICATION.</p>\r
+\r
+<h3>l. Export Control.</h3><p>The Licensed Application is subject to export control under the U.S. Commerce Department’s Export Administration Regulations (“EAR”).  Unless prior authorization is obtained from the U.S. Commerce Department, neither you nor your subsidiaries shall export, re-export, or release, directly or indirectly (including, without limitation, by permitting the Licensed Application to be downloaded), any technology, software, or software source code, received from TI, or export, directly or indirectly, any direct product of such technology, software, or software source code, to any person, destination or country to which the export, re-export, or release of the technology, software, or software source code, or direct product is prohibited by the EAR.  You represent and warrant that you (i) are not located in, or under the control of, a national or resident of Cuba, Iran, North Korea, Sudan and Syria or any other country subject to a U.S. goods embargo; (ii) are not on the U.S. Treasury Department’s List of Specially Designated Nationals or the U.S. Commerce Department’s Denied Persons List or Entity List; and (iii) will not use the Licensed Application or transfer the Licensed Application for use in any military, nuclear, chemical or biological weapons, or missile technology end-uses.  Any software export classification made by TI shall not be construed as a representation or warranty regarding the proper export classification for such software or whether an export license or other documentation is required for the exportation of such software.</p>\r
\r
+<h3>m. PRC Provisions.</h3><p>If you are located in the People’s Republic of China (“PRC”) or if the Licensed Application will be sent to the PRC, the following provisions shall apply:</p><p>\r
+i.     Registration Requirements. You shall be solely responsible for performing all acts and obtaining all approvals that may be required in connection with this Agreement by the government of the PRC, including but not limited to registering pursuant to, and otherwise complying with, the PRC Measures on the Administration of Software Products, Management Regulations on Technology Import-Export, and Technology Import and Export Contract Registration Management Rules. Upon receipt of such approvals from the government authorities, you shall forward evidence of all such approvals to TI for its records.  In the event that you fail to obtain any such approval or registration, you shall be solely responsible for any and all losses, damages or costs resulting therefrom, and shall indemnify TI for all such losses, damages or costs.</p>\r
+<p>\r
+ii.    Governing Language.  This Agreement is written and executed in the English language and shall be authoritative and controlling, whether or not translated into a language other than English to comply with law or for reference purposes.  If a translation of this Agreement is required for any purpose, including but not limited to registration of the Agreement pursuant to any governmental laws, regulations or rules, you shall be solely responsible for creating such translation.</p>  \r
+\r
+<h3>n. No Technical Support.</h3><p>TI and its licensors are under no obligation to install, maintain, or support the Licensed Application.</p>\r
+\r
+<h3>o. Trademarks and Logos.</h3>This Agreement does not grant You any rights to use any trademarks, logos or service marks belonging to TI.\r
+\r
+<h3>p. Governing Law and Severability; Waiver.</h3><p>This Agreement will be governed by and interpreted in accordance with the laws of the State of Texas, without reference to conflict of laws principles.  If for any reason a court of competent jurisdiction finds any provision of the Agreement to be unenforceable, that provision will be enforced to the maximum extent possible to effectuate the intent of the parties, and the remainder of the Agreement shall continue in full force and effect.  This Agreement shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods, or by the Uniform Computer Information Transactions Act (UCITA).  The parties agree that non-exclusive jurisdiction for any dispute arising out of or relating to this Agreement lies within the courts located in the State of Texas.  Notwithstanding the foregoing, any judgment may be enforced in any United States or foreign court, and either party may seek injunctive relief in any United States or foreign court.  Failure by TI to enforce any provision of this Agreement shall not be deemed a waiver of future enforcement of that or any other provision in this Agreement or any other agreement that may be in place between the parties. Your use of the Licensed Application may also be subject to other local, state, national, or international laws.</p>\r
+\r
+<h3>q. Notices.</h3><p>Except as otherwise indicated, all notices to TI hereunder shall be delivered to Texas Instruments Incorporated, 12500 TI Boulevard, Dallas, Texas 75243, Attention: Internet Marketing, with a copy to Texas Instruments Incorporated, 13588 N. Central Expressway, Mail Station 3999, Dallas, Texas 75243, Attention: Law Department – Sales &amp; Marketing. All notices shall be deemed served when received by TI.\r
+</p>\r
+       </div>\r
+</body>\r
+</html>\r
diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar
new file mode 100644 (file)
index 0000000..9056828
Binary files /dev/null and b/libs/android-support-v4.jar differ
diff --git a/project.properties b/project.properties
new file mode 100644 (file)
index 0000000..4ab1256
--- /dev/null
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-19
diff --git a/res/drawable-hdpi/bluetooth.png b/res/drawable-hdpi/bluetooth.png
new file mode 100644 (file)
index 0000000..adc7b42
Binary files /dev/null and b/res/drawable-hdpi/bluetooth.png differ
diff --git a/res/drawable-hdpi/ic_action_about.png b/res/drawable-hdpi/ic_action_about.png
new file mode 100644 (file)
index 0000000..077dcec
Binary files /dev/null and b/res/drawable-hdpi/ic_action_about.png differ
diff --git a/res/drawable-hdpi/ic_action_bluetooth.png b/res/drawable-hdpi/ic_action_bluetooth.png
new file mode 100644 (file)
index 0000000..eec6adf
Binary files /dev/null and b/res/drawable-hdpi/ic_action_bluetooth.png differ
diff --git a/res/drawable-hdpi/ic_action_cancel.png b/res/drawable-hdpi/ic_action_cancel.png
new file mode 100644 (file)
index 0000000..f889617
Binary files /dev/null and b/res/drawable-hdpi/ic_action_cancel.png differ
diff --git a/res/drawable-hdpi/ic_action_refresh.png b/res/drawable-hdpi/ic_action_refresh.png
new file mode 100644 (file)
index 0000000..45b2228
Binary files /dev/null and b/res/drawable-hdpi/ic_action_refresh.png differ
diff --git a/res/drawable-hdpi/ic_action_settings.png b/res/drawable-hdpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..0eb78f7
Binary files /dev/null and b/res/drawable-hdpi/ic_action_settings.png differ
diff --git a/res/drawable-hdpi/list_item_normal.xml b/res/drawable-hdpi/list_item_normal.xml
new file mode 100644 (file)
index 0000000..f8e8b46
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<shape xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:shape="rectangle" >\r
+\r
+    <gradient\r
+        android:angle="270"\r
+        android:centerColor="#333"\r
+        android:endColor="#666"\r
+        android:startColor="#666" />\r
+\r
+    <stroke\r
+        android:width="2dp"\r
+        android:color="#A0000000" />\r
+\r
+    <padding\r
+        android:bottom="8dp"\r
+        android:left="5dp"\r
+        android:right="5dp"\r
+        android:top="8dp" />\r
+\r
+    <corners android:radius="12dp" />\r
+\r
+</shape>
\ No newline at end of file
diff --git a/res/drawable-hdpi/tible.png b/res/drawable-hdpi/tible.png
new file mode 100644 (file)
index 0000000..385c985
Binary files /dev/null and b/res/drawable-hdpi/tible.png differ
diff --git a/res/drawable-mdpi/buttonsoffoff.png b/res/drawable-mdpi/buttonsoffoff.png
new file mode 100644 (file)
index 0000000..06aa7d3
Binary files /dev/null and b/res/drawable-mdpi/buttonsoffoff.png differ
diff --git a/res/drawable-mdpi/buttonsoffon.png b/res/drawable-mdpi/buttonsoffon.png
new file mode 100644 (file)
index 0000000..e83eb27
Binary files /dev/null and b/res/drawable-mdpi/buttonsoffon.png differ
diff --git a/res/drawable-mdpi/buttonsonoff.png b/res/drawable-mdpi/buttonsonoff.png
new file mode 100644 (file)
index 0000000..dfdcb6b
Binary files /dev/null and b/res/drawable-mdpi/buttonsonoff.png differ
diff --git a/res/drawable-mdpi/buttonsonon.png b/res/drawable-mdpi/buttonsonon.png
new file mode 100644 (file)
index 0000000..b48e688
Binary files /dev/null and b/res/drawable-mdpi/buttonsonon.png differ
diff --git a/res/drawable-mdpi/ic_action_about.png b/res/drawable-mdpi/ic_action_about.png
new file mode 100644 (file)
index 0000000..624e745
Binary files /dev/null and b/res/drawable-mdpi/ic_action_about.png differ
diff --git a/res/drawable-mdpi/ic_action_bluetooth.png b/res/drawable-mdpi/ic_action_bluetooth.png
new file mode 100644 (file)
index 0000000..e06e4f3
Binary files /dev/null and b/res/drawable-mdpi/ic_action_bluetooth.png differ
diff --git a/res/drawable-mdpi/ic_action_cancel.png b/res/drawable-mdpi/ic_action_cancel.png
new file mode 100644 (file)
index 0000000..e84853e
Binary files /dev/null and b/res/drawable-mdpi/ic_action_cancel.png differ
diff --git a/res/drawable-mdpi/ic_action_refresh.png b/res/drawable-mdpi/ic_action_refresh.png
new file mode 100644 (file)
index 0000000..de008e5
Binary files /dev/null and b/res/drawable-mdpi/ic_action_refresh.png differ
diff --git a/res/drawable-mdpi/ic_action_settings.png b/res/drawable-mdpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..c290e59
Binary files /dev/null and b/res/drawable-mdpi/ic_action_settings.png differ
diff --git a/res/drawable-mdpi/reed_closed.png b/res/drawable-mdpi/reed_closed.png
new file mode 100644 (file)
index 0000000..ec48fdb
Binary files /dev/null and b/res/drawable-mdpi/reed_closed.png differ
diff --git a/res/drawable-mdpi/reed_open.png b/res/drawable-mdpi/reed_open.png
new file mode 100644 (file)
index 0000000..128f258
Binary files /dev/null and b/res/drawable-mdpi/reed_open.png differ
diff --git a/res/drawable-mdpi/ti_stk_2c_pos_rgb_png.png b/res/drawable-mdpi/ti_stk_2c_pos_rgb_png.png
new file mode 100644 (file)
index 0000000..14025a0
Binary files /dev/null and b/res/drawable-mdpi/ti_stk_2c_pos_rgb_png.png differ
diff --git a/res/drawable-mdpi/tible.png b/res/drawable-mdpi/tible.png
new file mode 100644 (file)
index 0000000..1ed972a
Binary files /dev/null and b/res/drawable-mdpi/tible.png differ
diff --git a/res/drawable-xhdpi/accelerometer.png b/res/drawable-xhdpi/accelerometer.png
new file mode 100644 (file)
index 0000000..6eca220
Binary files /dev/null and b/res/drawable-xhdpi/accelerometer.png differ
diff --git a/res/drawable-xhdpi/barometer.png b/res/drawable-xhdpi/barometer.png
new file mode 100644 (file)
index 0000000..06bedfc
Binary files /dev/null and b/res/drawable-xhdpi/barometer.png differ
diff --git a/res/drawable-xhdpi/gyroscope.png b/res/drawable-xhdpi/gyroscope.png
new file mode 100644 (file)
index 0000000..30cff8d
Binary files /dev/null and b/res/drawable-xhdpi/gyroscope.png differ
diff --git a/res/drawable-xhdpi/humidity.png b/res/drawable-xhdpi/humidity.png
new file mode 100644 (file)
index 0000000..40d04ce
Binary files /dev/null and b/res/drawable-xhdpi/humidity.png differ
diff --git a/res/drawable-xhdpi/ic_action_about.png b/res/drawable-xhdpi/ic_action_about.png
new file mode 100644 (file)
index 0000000..3be3152
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_about.png differ
diff --git a/res/drawable-xhdpi/ic_action_bluetooth.png b/res/drawable-xhdpi/ic_action_bluetooth.png
new file mode 100644 (file)
index 0000000..f370b65
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_bluetooth.png differ
diff --git a/res/drawable-xhdpi/ic_action_cancel.png b/res/drawable-xhdpi/ic_action_cancel.png
new file mode 100644 (file)
index 0000000..58e2e3b
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_cancel.png differ
diff --git a/res/drawable-xhdpi/ic_action_refresh.png b/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644 (file)
index 0000000..cdc160d
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_refresh.png differ
diff --git a/res/drawable-xhdpi/ic_action_settings.png b/res/drawable-xhdpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..999d0f0
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_settings.png differ
diff --git a/res/drawable-xhdpi/irtemperature.png b/res/drawable-xhdpi/irtemperature.png
new file mode 100644 (file)
index 0000000..a38242b
Binary files /dev/null and b/res/drawable-xhdpi/irtemperature.png differ
diff --git a/res/drawable-xhdpi/lightsensor.png b/res/drawable-xhdpi/lightsensor.png
new file mode 100644 (file)
index 0000000..b671ac4
Binary files /dev/null and b/res/drawable-xhdpi/lightsensor.png differ
diff --git a/res/drawable-xhdpi/reedrelay.png b/res/drawable-xhdpi/reedrelay.png
new file mode 100644 (file)
index 0000000..7da2ffc
Binary files /dev/null and b/res/drawable-xhdpi/reedrelay.png differ
diff --git a/res/drawable-xhdpi/sensortag.png b/res/drawable-xhdpi/sensortag.png
new file mode 100644 (file)
index 0000000..e925fc0
Binary files /dev/null and b/res/drawable-xhdpi/sensortag.png differ
diff --git a/res/drawable-xhdpi/sensortag_magnetometer.png b/res/drawable-xhdpi/sensortag_magnetometer.png
new file mode 100644 (file)
index 0000000..e3123ed
Binary files /dev/null and b/res/drawable-xhdpi/sensortag_magnetometer.png differ
diff --git a/res/drawable-xhdpi/sensortag_simplekeys.png b/res/drawable-xhdpi/sensortag_simplekeys.png
new file mode 100644 (file)
index 0000000..adad73a
Binary files /dev/null and b/res/drawable-xhdpi/sensortag_simplekeys.png differ
diff --git a/res/drawable-xhdpi/st2.png b/res/drawable-xhdpi/st2.png
new file mode 100644 (file)
index 0000000..d3ba7e1
Binary files /dev/null and b/res/drawable-xhdpi/st2.png differ
diff --git a/res/drawable-xhdpi/temperature.png b/res/drawable-xhdpi/temperature.png
new file mode 100644 (file)
index 0000000..22648f1
Binary files /dev/null and b/res/drawable-xhdpi/temperature.png differ
diff --git a/res/drawable-xhdpi/tible.png b/res/drawable-xhdpi/tible.png
new file mode 100644 (file)
index 0000000..2f8a3c7
Binary files /dev/null and b/res/drawable-xhdpi/tible.png differ
diff --git a/res/drawable-xhdpi/unknown.png b/res/drawable-xhdpi/unknown.png
new file mode 100644 (file)
index 0000000..ba78c7f
Binary files /dev/null and b/res/drawable-xhdpi/unknown.png differ
diff --git a/res/drawable-xxhdpi/ic_action_about.png b/res/drawable-xxhdpi/ic_action_about.png
new file mode 100644 (file)
index 0000000..0fe809b
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_about.png differ
diff --git a/res/drawable-xxhdpi/ic_action_bluetooth.png b/res/drawable-xxhdpi/ic_action_bluetooth.png
new file mode 100644 (file)
index 0000000..0c0f1ac
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_bluetooth.png differ
diff --git a/res/drawable-xxhdpi/ic_action_cancel.png b/res/drawable-xxhdpi/ic_action_cancel.png
new file mode 100644 (file)
index 0000000..a9bbcde
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_cancel.png differ
diff --git a/res/drawable-xxhdpi/ic_action_refresh.png b/res/drawable-xxhdpi/ic_action_refresh.png
new file mode 100644 (file)
index 0000000..cb847f3
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_refresh.png differ
diff --git a/res/drawable-xxhdpi/ic_action_settings.png b/res/drawable-xxhdpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..530227e
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_settings.png differ
diff --git a/res/layout/activity_file.xml b/res/layout/activity_file.xml
new file mode 100644 (file)
index 0000000..9f150cf
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:tools="http://schemas.android.com/tools"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:orientation="vertical"\r
+    tools:context=".FileActivity" >\r
+\r
+    <TextView\r
+        android:id="@+id/tw_directory"\r
+        style="@style/dirStyle"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content" />\r
+\r
+    <ListView\r
+        android:id="@+id/lw_file"\r
+        style="@style/devlistStyle"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="0dp"\r
+        android:layout_weight="2"\r
+        android:choiceMode="singleChoice"\r
+        android:padding="3dp" />\r
+\r
+    <Button\r
+        android:id="@+id/btn_confirm"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:onClick="onConfirm"\r
+        android:text="@string/btn_txt_confirm" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/activity_fwupdate.xml b/res/layout/activity_fwupdate.xml
new file mode 100644 (file)
index 0000000..856297b
--- /dev/null
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:layout_margin="10dip"\r
+    android:orientation="vertical" >\r
+\r
+    <LinearLayout\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:gravity="left"\r
+        android:orientation="horizontal"\r
+        android:paddingBottom="10dp"\r
+        android:paddingTop="10dp" >\r
+\r
+        <TextView\r
+            style="@style/nameStyle"\r
+            android:layout_width="0dp"\r
+            android:layout_height="fill_parent"\r
+            android:layout_gravity="left|center_vertical"\r
+            android:layout_weight="1"\r
+            android:text="@string/cur_image" />\r
+\r
+        <TextView\r
+            android:id="@+id/tw_target"\r
+            style="@style/dataStyle1"\r
+            android:layout_width="0dp"\r
+            android:layout_height="fill_parent"\r
+            android:layout_weight="1.5"\r
+            android:text="@string/no_image" />\r
+    </LinearLayout>\r
+\r
+    <LinearLayout\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:gravity="left"\r
+        android:orientation="horizontal"\r
+        android:paddingBottom="10dp"\r
+        android:paddingTop="10dp" >\r
+\r
+        <TextView\r
+            style="@style/nameStyle"\r
+            android:layout_width="0dp"\r
+            android:layout_height="fill_parent"\r
+            android:layout_gravity="left|center_vertical"\r
+            android:layout_weight="1"\r
+            android:text="@string/new_image" />\r
+\r
+        <TextView\r
+            android:id="@+id/tw_file"\r
+            style="@style/dataStyle1"\r
+            android:layout_width="0dp"\r
+            android:layout_height="fill_parent"\r
+            android:layout_weight="1.5"\r
+            android:gravity="left"\r
+            android:text="@string/no_image_sel"\r
+            android:textAlignment="gravity" />\r
+    </LinearLayout>\r
+\r
+    <LinearLayout\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:gravity="center"\r
+        android:orientation="horizontal"\r
+        android:paddingBottom="5dp"\r
+        android:paddingTop="5dp" >\r
+\r
+        <Button\r
+            android:id="@+id/btn_load_a"\r
+            style="?android:attr/buttonStyle"\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="fill_parent"\r
+            android:layout_gravity="center"\r
+            android:gravity="center"\r
+            android:onClick="onLoad"\r
+            android:text="@string/load_image_a" />\r
+\r
+        <Button\r
+            android:id="@+id/btn_load_b"\r
+            style="?android:attr/buttonStyle"\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="fill_parent"\r
+            android:layout_gravity="center"\r
+            android:onClick="onLoad"\r
+            android:text="@string/load_image_b" />\r
+\r
+        <Button\r
+            android:id="@+id/btn_load_c"\r
+            style="?android:attr/buttonStyle"\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="fill_parent"\r
+            android:layout_gravity="center"\r
+            android:onClick="onLoadCustom"\r
+            android:text="@string/load_image_c" />\r
+    </LinearLayout>\r
+\r
+    <TextView\r
+        android:id="@+id/tw_info"\r
+        style="@style/dataStyle"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="center"\r
+        android:layout_marginBottom="5dp"\r
+        android:layout_weight="0"\r
+        android:gravity="center_horizontal"\r
+        android:text="@string/idle"\r
+        android:textSize="14dp" />\r
+\r
+    <ProgressBar\r
+        android:id="@+id/pb_progress"\r
+        style="@android:style/Widget.ProgressBar.Horizontal"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_marginBottom="5dp"\r
+        android:indeterminate="false"\r
+        android:max="100"\r
+        android:maxHeight="15dp"\r
+        android:minHeight="15dp"\r
+        android:progress="0" />\r
+\r
+    <TextView\r
+        android:id="@+id/tw_log"\r
+        style="@style/logStyle"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="bottom"\r
+        android:layout_weight="1"\r
+        android:lines="10"\r
+        android:padding="5dp" />\r
+\r
+    <Button\r
+        android:id="@+id/btn_start"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="bottom"\r
+        android:layout_weight="0"\r
+        android:onClick="onStart"\r
+        android:text="@string/start_prog" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/dialog_about.xml b/res/layout/dialog_about.xml
new file mode 100644 (file)
index 0000000..36f2198
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:fadingEdge="horizontal|vertical"\r
+    android:orientation="vertical" >\r
+\r
+    <TextView\r
+        android:id="@+id/title"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:gravity="center_horizontal"\r
+        android:padding="5dp"\r
+        android:textAlignment="center"\r
+        android:textColor="#c00"\r
+        android:textSize="24dp" />\r
+\r
+    <TextView\r
+        android:id="@+id/header"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:gravity="center_horizontal"\r
+        android:padding="3dp"\r
+        android:textAlignment="center"\r
+        android:textSize="16dp" />\r
+\r
+    <WebView\r
+        android:id="@+id/web_content"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_margin="5dp" />\r
+\r
+    <TextView\r
+        android:id="@+id/footer"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:gravity="center_horizontal"\r
+        android:padding="10dp"\r
+        android:textAlignment="center"\r
+        android:textSize="16dp" />\r
+\r
+    <Button\r
+        android:id="@+id/buttonOK"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_margin="0dp"\r
+        android:text="@android:string/ok" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/dialog_license.xml b/res/layout/dialog_license.xml
new file mode 100644 (file)
index 0000000..0cb5864
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:fadingEdge="horizontal|vertical"\r
+    android:orientation="vertical" >\r
+\r
+    <Button\r
+        android:id="@+id/buttonOK"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_margin="0dp"\r
+        android:text="@string/agree" />\r
+    \r
+    <WebView\r
+        android:id="@+id/webpage_license"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="fill_parent" />\r
+\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/element_characteristic.xml b/res/layout/element_characteristic.xml
new file mode 100644 (file)
index 0000000..67b3bf4
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    style="@style/listItemStyle"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent" >\r
+\r
+    <TextView\r
+        android:id="@+id/name"\r
+        style="@style/nameStyle"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignParentTop="true"\r
+        android:gravity="left" />\r
+\r
+    <TextView\r
+        android:id="@+id/uuid"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignParentBottom="true"\r
+        android:gravity="center" />\r
+\r
+    <TextView\r
+        android:id="@+id/info"\r
+        style="@style/infoStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignParentRight="true"\r
+        android:layout_below="@id/name"\r
+        android:gravity="center" />\r
+\r
+</RelativeLayout>\r
diff --git a/res/layout/element_device.xml b/res/layout/element_device.xml
new file mode 100644 (file)
index 0000000..8276677
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:tools="http://schemas.android.com/tools"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:orientation="horizontal"\r
+    android:paddingBottom="5dp"\r
+    >\r
+\r
+    <ImageView\r
+        android:layout_width="80dp"\r
+        android:layout_height="wrap_content"\r
+        android:id="@+id/devImage"\r
+        android:layout_gravity="left|center_vertical"\r
+        android:layout_weight="0"\r
+        android:contentDescription="@string/image"\r
+        android:focusable="false"\r
+        android:paddingRight="5dp"\r
+        android:src="@drawable/sensortag" />\r
+\r
+    <TextView\r
+        android:id="@+id/descr"\r
+        style="@style/nameStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="left|center_vertical"\r
+        android:layout_weight="4"\r
+        android:focusable="false"\r
+        android:gravity="left" />\r
+\r
+    <Button\r
+        android:id="@+id/btnConnect"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="center_vertical"\r
+        android:layout_weight="0"\r
+        android:clickable="false"\r
+        android:focusable="false"\r
+        android:gravity="center"\r
+        android:text="@string/connect" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/element_file.xml b/res/layout/element_file.xml
new file mode 100644 (file)
index 0000000..42c0ea9
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    style="@style/listItemStyle"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent" >\r
+\r
+    <TextView\r
+        android:id="@+id/name"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignParentTop="true"\r
+        android:gravity="left" />\r
+\r
+</RelativeLayout>\r
diff --git a/res/layout/fragment_help.xml b/res/layout/fragment_help.xml
new file mode 100644 (file)
index 0000000..854eadf
--- /dev/null
@@ -0,0 +1,12 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:tools="http://schemas.android.com/tools"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    tools:context=".MainActivity$HelpFragment" >\r
+\r
+    <WebView\r
+        android:id="@+id/webpage"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="fill_parent" />\r
+\r
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/fragment_pager.xml b/res/layout/fragment_pager.xml
new file mode 100644 (file)
index 0000000..7fbce40
--- /dev/null
@@ -0,0 +1,5 @@
+<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:tools="http://schemas.android.com/tools"\r
+    android:id="@+id/pager"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent" />\r
diff --git a/res/layout/fragment_scan.xml b/res/layout/fragment_scan.xml
new file mode 100644 (file)
index 0000000..f3e9c3e
--- /dev/null
@@ -0,0 +1,64 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:tools="http://schemas.android.com/tools"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:layout_margin="10dp"\r
+    android:clickable="false"\r
+    android:gravity="bottom"\r
+    android:longClickable="false"\r
+    android:orientation="vertical"\r
+    android:padding="0dp"\r
+    tools:context=".MainActivity" >\r
+\r
+    <ListView\r
+        android:id="@+id/device_list"\r
+        style="@style/devlistStyle"\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="0dp"\r
+        android:layout_margin="10dp"\r
+        android:layout_weight="2"\r
+        android:choiceMode="singleChoice"\r
+        android:padding="3dp" />\r
+\r
+    <TextView\r
+        android:id="@+id/no_device"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="center_horizontal"\r
+        android:layout_margin="50dp"\r
+        android:gravity="center"\r
+        android:text="@string/nodevice"\r
+        android:textSize="14sp" />\r
+\r
+    <ImageView\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="center_horizontal"\r
+        android:layout_marginBottom="50dp"\r
+        android:layout_marginLeft="20dp"\r
+        android:layout_marginRight="20dp"\r
+        android:layout_marginTop="20dp"\r
+        android:contentDescription="@string/image"\r
+        android:gravity="center"\r
+        android:src="@drawable/ti_stk_2c_pos_rgb_png" />\r
+\r
+    <TextView\r
+        android:id="@+id/status"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="30dp"\r
+        android:gravity="center"\r
+        android:textSize="12sp" />\r
+\r
+    <Button\r
+        android:id="@+id/btn_scan"\r
+        android:drawableLeft="@drawable/ic_action_refresh"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:fadingEdge="vertical"\r
+        android:gravity="center_horizontal|center"\r
+        android:linksClickable="false"\r
+        android:onClick="onBtnScan"\r
+        android:padding="10dp"\r
+        android:text="@string/button_scan" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/frame_progress.xml b/res/layout/frame_progress.xml
new file mode 100644 (file)
index 0000000..f4c15b2
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+   android:layout_height="wrap_content"\r
+   android:layout_width="56dp"\r
+   android:minWidth="56dp">\r
+    <ProgressBar android:layout_width="32dp"\r
+       android:layout_height="32dp"\r
+       android:layout_gravity="center"/>\r
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/services_browser.xml b/res/layout/services_browser.xml
new file mode 100644 (file)
index 0000000..a04f1a9
--- /dev/null
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="fill_parent"\r
+    android:orientation="vertical" >\r
+    \r
+    <TableLayout\r
+        android:id="@+id/services_browser_layout"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:shrinkColumns="*"\r
+        android:stretchColumns="*" >\r
+        \r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/keys" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/keyPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/sensortag_simplekeys" />\r
+\r
+            <ImageView\r
+                android:id="@+id/buttons"\r
+                android:layout_height="wrap_content"\r
+                android:layout_span="2"\r
+                android:contentDescription="@string/image"\r
+                android:src="@drawable/buttonsoffoff" />\r
+\r
+            <TextView android:layout_span="1" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/acc" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/accPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/accelerometer" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/xyz3" />\r
+\r
+            <TextView\r
+                android:id="@+id/accelerometerTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty3" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitG3" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/mag" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/magPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/sensortag_magnetometer" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/xyz3" />\r
+\r
+            <TextView\r
+                android:id="@+id/magnetometerTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty3" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitT3" />\r
+        </TableRow>\r
+        \r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/gyro" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/gyrPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/gyroscope" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/xyz3" />\r
+\r
+            <TextView\r
+                android:id="@+id/gyroscopeTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty3" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitDegSec3" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/tObj" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/objPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/irtemperature" />\r
+\r
+            <TextView style="@style/ServiceItem" />\r
+\r
+            <TextView\r
+                android:id="@+id/objTemperatureText"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitDeg" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/tAmb" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/ambPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/temperature" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/ambientTemperatureTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitDeg" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/hum" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/humPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/humidity" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/humidityTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitRH" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/bar" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/barPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/barometer" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/barometerTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitPA_Meter" />\r
+        </TableRow>\r
+        \r
+        </TableLayout>\r
+</ScrollView>
\ No newline at end of file
diff --git a/res/layout/services_browser2.xml b/res/layout/services_browser2.xml
new file mode 100644 (file)
index 0000000..2e5a23d
--- /dev/null
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="fill_parent"\r
+    android:orientation="vertical" >\r
+\r
+    <TableLayout\r
+        android:id="@+id/services_browser_layout2"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:shrinkColumns="*"\r
+        android:stretchColumns="*" >\r
+        \r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/keys" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/keyPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <!--  TextView android:drawableLeft="@drawable/sensortag_simplekeys" />  -->\r
+\r
+            <ImageView\r
+                android:id="@+id/buttons"\r
+                android:layout_span="2"\r
+                android:layout_height="wrap_content"\r
+                android:contentDescription="@string/image"\r
+                android:src="@drawable/buttonsoffoff" />\r
+\r
+            <ImageView\r
+                android:id="@+id/relay"\r
+                android:layout_span="2"\r
+                android:layout_height="wrap_content"\r
+                android:contentDescription="@string/image"\r
+                android:src="@drawable/reed_closed" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/acc" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/accPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/accelerometer" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/xyz3" />\r
+\r
+            <TextView\r
+                android:id="@+id/accelerometerTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty3" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitG3" />\r
+        </TableRow>\r
+        \r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/lux" />\r
+        </TableRow>\r
+        \r
+        <TableRow\r
+            android:id="@+id/luxPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/lightsensor" />\r
+            \r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/luxometerTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitLux" />\r
+        </TableRow>\r
+        \r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/gyro" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/gyrPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/gyroscope" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/xyz3" />\r
+\r
+            <TextView\r
+                android:id="@+id/gyroscopeTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty3" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitDegSec3" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/tObj" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/objPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/irtemperature" />\r
+\r
+            <TextView style="@style/ServiceItem" />\r
+\r
+            <TextView\r
+                android:id="@+id/objTemperatureText"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitDeg" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/tAmb" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/ambPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/temperature" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/ambientTemperatureTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitDeg" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/hum" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/humPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/humidity" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/humidityTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitRH" />\r
+        </TableRow>\r
+\r
+        <TableRow style="@style/ServiceHeaderRow" >\r
+\r
+            <TextView\r
+                style="@style/ServiceHeaderItem"\r
+                android:text="@string/bar" />\r
+        </TableRow>\r
+\r
+        <TableRow\r
+            android:id="@+id/barPanel"\r
+            style="@style/ServiceRow" >\r
+\r
+            <TextView android:drawableLeft="@drawable/barometer" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="" />\r
+\r
+            <TextView\r
+                android:id="@+id/barometerTxt"\r
+                style="@style/ServiceItemValue"\r
+                android:text="@string/empty1" />\r
+\r
+            <TextView\r
+                style="@style/ServiceItem"\r
+                android:text="@string/unitPA_Meter" />\r
+        </TableRow>\r
+        \r
+    </TableLayout>\r
+    \r
+</ScrollView>
\ No newline at end of file
diff --git a/res/menu/device_activity_actions.xml b/res/menu/device_activity_actions.xml
new file mode 100644 (file)
index 0000000..3dccce6
--- /dev/null
@@ -0,0 +1,23 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >\r
+\r
+     <item\r
+        android:id="@+id/opt_progress"\r
+        android:showAsAction="always"\r
+        android:title="@string/progress"\r
+        android:visibility="invisible"\r
+        />\r
+    <item\r
+        android:id="@+id/opt_prefs"\r
+        android:orderInCategory="1"\r
+        android:showAsAction="ifRoom"\r
+        android:icon="@drawable/ic_action_settings" \r
+        android:title="@string/prefs"/>\r
+    <item\r
+        android:id="@+id/opt_fwupdate"\r
+        android:title="@string/fwupdate"/>\r
+    <item\r
+        android:id="@+id/opt_about"\r
+        android:icon="@drawable/ic_action_about" \r
+        android:title="@string/about"/>\r
+\r
+</menu>
\ No newline at end of file
diff --git a/res/menu/main_activity_actions.xml b/res/menu/main_activity_actions.xml
new file mode 100644 (file)
index 0000000..0eefb1e
--- /dev/null
@@ -0,0 +1,34 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >\r
+\r
+     <item\r
+        android:id="@+id/opt_progress"\r
+        android:showAsAction="always"\r
+        android:title="@string/progress"\r
+        android:visibility="invisible"\r
+        />\r
+    <item\r
+        android:id="@+id/opt_bt"\r
+        android:showAsAction="ifRoom"\r
+        android:orderInCategory="1"\r
+        android:icon="@drawable/ic_action_bluetooth"\r
+        android:title="@string/bt" \r
+        />\r
+    <item\r
+        android:id="@+id/opt_e2e"\r
+        android:title="@string/tie2e"/>\r
+    <item\r
+        android:id="@+id/opt_sthome"\r
+        android:title="@string/sthome"/>\r
+    <item\r
+        android:id="@+id/opt_license"\r
+        android:title="@string/license"/>\r
+    <item\r
+        android:id="@+id/opt_about"\r
+        android:icon="@drawable/ic_action_about"\r
+        android:title="@string/about"/>\r
+    <item\r
+        android:id="@+id/opt_exit"\r
+        android:title="@string/exit"/>\r
+\r
+\r
+</menu>\r
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644 (file)
index 0000000..2d98ea3
--- /dev/null
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<resources>\r
+\r
+    <!-- Main activity -->\r
+    <string name="app_name">BLE SensorTag</string>\r
+    <string name="button_scan">Scan</string>\r
+    <string name="connect">Connect</string>\r
+    <string name="title_device_list">Device List</string>\r
+    <string name="device">Device</string>\r
+    <string name="header">Available BLE Devices</string>\r
+    <string name="disconnected">Device is not connected</string>\r
+    <string name="control">Done</string>\r
+    <string name="bt_not_supported">Bluetooth is not supported</string>\r
+    <string name="ble_not_supported">BLE is not supported</string>\r
+    <string name="bt_on">Bluetooth was turned  on</string>\r
+    <string name="bt_not_on">Bluetooth was not turned on</string>\r
+    <string name="app_closing">Exiting BLE SensorTag app</string>\r
+    <string-array name="device_filter"><item>SensorTag</item><item>SensorTag2</item></string-array>    \r
+    <string name="nodevice">There are no SensorTags advertising within range. Please push the side button on the SensorTag to start advertising.</string>\r
+    <string name="scan_advice">The Android device is not scanning. Please tap \'Scan\' to scan for SensorTags.</string>\r
+    <string name="bt_adapter_disable">Disable Bluetooth adapter</string>\r
+    <string name="bt_adapter_reset">Reset Bluetooth adapter</string>\r
+    \r
+    <!-- Options menu -->\r
+    <string name="prefs">Preferences</string>\r
+    <string name="progress"></string>\r
+    <string name="agree">I agree</string>\r
+    <string name="fwupdate">Firmware update</string>\r
+    <string name="bt">Bluetooth Adapter</string>\r
+    <string name="sthome">SensorTag Home</string>\r
+    <string name="tie2e">TI E2E Community</string>\r
+    <string name="license">License</string>\r
+    <string name="about">About</string>\r
+    <string name="exit">Exit</string>\r
+\r
+    <!-- Device activity -->\r
+    <string name="dev_addr">Device address</string>\r
+    <string name="image">Image</string>\r
+    \r
+    <!-- Sensor names-->\r
+    <string name="keys">Keys</string>\r
+    <string name="acc">Accelerometer</string>\r
+    <string name="mag">Magnetometer</string>\r
+    <string name="lux">Luxometer</string>\r
+    <string name="gyro">Gyroscope</string>\r
+    <string name="hum">Humidity</string>\r
+    <string name="bar">Barometer</string>\r
+    <string name="tAmb">Ambience Temperature</string>\r
+    <string name="tObj">Object Temperature</string>\r
+    \r
+    <!-- Sensor misc. -->\r
+    <string name="xyz3">x:\ny:\nz:\n</string>\r
+    <string name="empty3">*\n*\n*\n</string>\r
+    <string name="unitDegSec3">deg/s\ndeg/s\ndeg/s\n</string>\r
+    <string name="unitG3">g\ng\ng\n</string>\r
+    <string name="unitT3">uT\nuT\nuT\n</string>\r
+    \r
+    <string name="empty1">*\n</string>\r
+    <string name="unitDeg">deg/C\n</string>\r
+    <string name="unitRH">%rH\n</string>\r
+    <string name="unitPA_Meter">nPA\nmeter</string>\r
+    <string name="unitLux">Lux\n</string>\r
+    \r
+    <!-- FWUpdate activity -->\r
+    <string name="title_oad">Firmware Update (OAD)</string>\r
+    <string name="start_prog">Start Programming</string>\r
+    <string name="cancel">Cancel</string>\r
+    <string name="prog_ogoing">NB! Not permitted to close this view during OAD transfer</string>\r
+    <string name="load_image_a">Image A</string>\r
+    <string name="load_image_b">Image B</string>\r
+    <string name="load_image_c">Custom</string>\r
+    <string name="no_image">Not an OAD image</string>\r
+    <string name="no_image_sel">No image selected</string>\r
+    <string name="new_image">New image:</string>\r
+    <string name="cur_image">Current image:</string>\r
+    <string name="idle">idle</string>\r
+    <string name="btn_txt_confirm">Confirm</string>\r
+\r
+</resources>\r
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644 (file)
index 0000000..13d72dc
--- /dev/null
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<resources>\r
+\r
+    <!--\r
+        Base application theme, dependent on API level. This theme is replaced\r
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\r\r\r\r
+    -->\r
+    <style name="AppBaseTheme" parent="android:Theme.Light">\r
+        <!--\r
+            Theme customizations available in newer API levels can go in\r
+            res/values-vXX/styles.xml, while customizations related to\r
+            backward-compatibility can go here.\r
+        -->\r
+    </style>\r
+\r
+    <!-- Application theme. -->\r
+    <style name="AppTheme" parent="AppBaseTheme">\r
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\r
+    </style>\r
+\r
+    <style name="aboutStyle">\r
+        <item name="android:background">@android:color/black</item>\r
+        <item name="android:textColor">#ff0</item>\r
+        <item name="android:textSize">14dp</item>\r
+    </style>\r
+\r
+    <style name="logStyle">\r
+        <item name="android:background">#dde</item>\r
+        <item name="android:textColor">@android:color/black</item>\r
+        <item name="android:textSize">18dp</item>\r
+    </style>\r
+\r
+    <style name="tabwidgetStyle">\r
+        <item name="android:background">#336</item>\r
+    </style>\r
+\r
+    <style name="devlistStyle">\r
+        <item name="android:dividerHeight">5dp</item>\r
+    </style>\r
+\r
+    <style name="listItemStyle">\r
+        <item name="android:background">#abc</item>\r
+        <item name="android:padding">18dp</item>\r
+    </style>\r
+\r
+    <style name="nameStyle">\r
+        <item name="android:textColor">#000</item>\r
+        <item name="android:textSize">18dp</item>\r
+    </style>\r
+\r
+    <style name="nameStyle.inactive">\r
+        <item name="android:textColor">#ccc</item>\r
+    </style>\r
+\r
+    <style name="nameStyleSelected">\r
+        <item name="android:textColor">#c33</item>\r
+    </style>\r
+\r
+    <style name="dirStyle">\r
+        <item name="android:textColor">#003</item>\r
+                               <item name="android:textSize">20dp</item>\r
+                               <item name="android:layout_margin">10dp</item>\r
+                               <item name="android:gravity">center_horizontal</item>\r
+    </style>\r
+    \r
+    <style name="dataStyle">\r
+        <item name="android:background">#fff</item>\r
+        <item name="android:textSize">16dp</item>\r
+        <item name="android:textColor">#030</item>\r
+        <item name="android:textColorHint">#fff</item>\r
+        <item name="android:layout_height">40dp</item>\r
+        <item name="android:padding">8dp</item>\r
+    </style>\r
+\r
+    <style name="dataStyle1">\r
+        <item name="android:textColor">#060</item>\r
+        <item name="android:textSize">16dp</item>\r
+    </style>\r
+\r
+    <style name="dataStyle2">\r
+        <item name="android:textColor">#f33</item>\r
+        <item name="android:textSize">16dp</item>\r
+    </style>\r
+\r
+    <style name="infoStyle">\r
+        <item name="android:textColor">#3f3</item>\r
+        <item name="android:textSize">14dp</item>\r
+    </style>\r
+\r
+    <style name="statusStyle">\r
+        <item name="android:layout_width">match_parent</item>\r
+        <item name="android:layout_height">wrap_content</item>\r
+        <item name="android:layout_marginTop">5dp</item>\r
+        <item name="android:layout_marginBottom">5dp</item>\r
+        <item name="android:gravity">right</item>\r
+        <item name="android:textSize">18dp</item>\r
+        <item name="android:background">#ccc</item>\r
+    </style>\r
+\r
+    <style name="statusStyleSmall">\r
+        <item name="android:layout_width">match_parent</item>\r
+        <item name="android:layout_height">wrap_content</item>\r
+        <item name="android:layout_marginBottom">10dp</item>\r
+        <item name="android:textSize">14dp</item>\r
+    </style>\r
+\r
+    <style name="statusStyle.Success" parent="statusStyle">\r
+        <item name="android:textColor">#336633</item>\r
+    </style>\r
+\r
+    <style name="statusStyle.Busy" parent="statusStyle">\r
+        <item name="android:textColor">#EEEEEE</item>\r
+    </style>\r
+\r
+    <style name="statusStyle.Failure" parent="statusStyle">\r
+        <item name="android:textColor">#FF0000</item>\r
+    </style>\r
+\r
+    <style name="statusStyle.Disabled" parent="statusStyle">\r
+        <item name="android:textColor">#999999</item>\r
+        <item name="android:gravity">right</item>\r
+    </style>\r
+\r
+    <style name="tbStartStyle">\r
+        <item name="android:textSize">16dp</item>\r
+    </style>\r
+\r
+    \r
+    <style name="ServiceHeaderRow">\r
+        <item name="android:layout_width">match_parent</item>\r
+        <item name="android:layout_height">wrap_content</item>\r
+        <item name="android:gravity">center</item>\r
+        <item name="android:typeface">serif</item>\r
+    </style>\r
+\r
+    <style name="ServiceHeaderItem">\r
+        <item name="android:layout_span">4</item>\r
+        <item name="android:textSize">20dp</item>\r
+        <item name="android:textStyle">bold</item>\r
+        <item name="android:gravity">center</item>\r
+    </style>\r
+\r
+    <style name="ServiceRow">\r
+        <item name="android:layout_width">match_parent</item>\r
+        <item name="android:layout_height">wrap_content</item>\r
+        <item name="android:background">#def</item>\r
+        <item name="android:gravity">center</item>\r
+    </style>\r
+\r
+    <style name="ServiceItem">\r
+        <item name="android:layout_width">match_parent</item>\r
+        <item name="android:layout_height">wrap_content</item>\r
+        <item name="android:typeface">monospace</item>\r
+        <item name="android:layout_marginTop">10dp</item>\r
+        <item name="android:textSize">18dp</item>\r
+    </style>\r
+    \r
+    <style name="ServiceItemValue">\r
+        <item name="android:layout_width">match_parent</item>\r
+        <item name="android:layout_height">wrap_content</item>\r
+        <item name="android:typeface">monospace</item>\r
+        <item name="android:gravity">right</item>\r
+        <item name="android:layout_marginTop">10dp</item>\r
+        <item name="android:layout_marginRight">30dp</item>\r
+        <item name="android:textSize">18dp</item>\r
+    </style>\r
+</resources>\r
diff --git a/res/xml/gatt_uuid.xml b/res/xml/gatt_uuid.xml
new file mode 100644 (file)
index 0000000..fb3d7dc
--- /dev/null
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<gattuuid>\r
+  <profile>\r
+    <name>Gatt</name>\r
+    <group>Descriptors<item uuid="0x2900">Characteristic Extended Properties</item><item uuid="0x2901">Characteristic User Description</item><item uuid="0x2902" descr="Write &quot;01:00&quot; to enable notifications, &quot;00:00&quot; to disable">Client Characteristic Configuration</item><item uuid="0x2903">Server Characteristic Configuration</item><item uuid="0x2904">Characteristic Presentation Format</item><item uuid="0x2905">Characteristic Aggregate Format</item><item uuid="0x2906">Valid Range</item><item uuid="0x2907">External Report Reference</item><item uuid="0x2908">Report Reference</item></group>\r
+    <group>Characteristics<item uuid="0x2A00">Device Name</item><item uuid="0x2A01">Appearance</item><item uuid="0x2A02">Peripheral Privacy Flag</item><item uuid="0x2A03">Reconnection Address</item><item uuid="0x2A04">Peripheral Preferred Connection Parameters</item><item uuid="0x2A05">Service Changed</item><item uuid="0x2A06">Alert Level</item><item uuid="0x2A07">Tx Power Level</item><item uuid="0x2A08">Date Time</item><item uuid="0x2A09">Day of Week</item><item uuid="0x2A0A">Day Date Time</item><item uuid="0x2A0C">Exact Time 256</item><item uuid="0x2A0D">DST Offset</item><item uuid="0x2A0E">Time Zone</item><item uuid="0x2A0F">Local Time Information</item><item uuid="0x2A11">Time with DST</item><item uuid="0x2A12">Time Accuracy</item><item uuid="0x2A13">Time Source</item><item uuid="0x2A14">Reference Time Information</item><item uuid="0x2A16">Time Update Control Point</item><item uuid="0x2A17">Time Update State</item><item uuid="0x2A18">Glucose Measurement</item><item uuid="0x2A19">Battery Level</item><item uuid="0x2A1C">Temperature Measurement</item><item uuid="0x2A1D">Temperature Type</item><item uuid="0x2A1E">Intermediate Temperature</item><item uuid="0x2A21">Measurement Interval</item><item uuid="0x2A22">Boot Keyboard Input Report</item><item uuid="0x2A23">System ID</item><item uuid="0x2A24">Model Number String</item><item uuid="0x2A25">Serial Number String</item><item uuid="0x2A26">Firmware Revision String</item><item uuid="0x2A27">Hardware Revision String</item><item uuid="0x2A28">Software Revision String</item><item uuid="0x2A29">Manufacturer Name String</item><item uuid="0x2A2A">IEEE 11073-20601 Regulatory Certification Data List</item><item uuid="0x2A2B">Current Time</item><item uuid="0x2A31">Scan Refresh</item><item uuid="0x2A32">Boot Keyboard Output Report</item><item uuid="0x2A33">Boot Mouse Input Report</item><item uuid="0x2A34">Glucose Measurement Context</item><item uuid="0x2A35">Blood Pressure Measurement</item><item uuid="0x2A36">Intermediate Cuff Pressure</item><item uuid="0x2A37">Heart Rate Measurement</item><item uuid="0x2A38">Body Sensor Location</item><item uuid="0x2A39">Heart Rate Control Point</item><item uuid="0x2A3F">Alert Status</item><item uuid="0x2A40">Ringer Control Point</item><item uuid="0x2A41">Ringer Setting</item><item uuid="0x2A42">Alert Category ID Bit Mask</item><item uuid="0x2A43">Alert Category ID</item><item uuid="0x2A44">Alert Notification Control Point</item><item uuid="0x2A45">Unread Alert Status</item><item uuid="0x2A46">New Alert</item><item uuid="0x2A47">Supported New Alert Category</item><item uuid="0x2A48">Supported Unread Alert Category</item><item uuid="0x2A49">Blood Pressure Feature</item><item uuid="0x2A4A">HID Information</item><item uuid="0x2A4B">Report Map</item><item uuid="0x2A4C">HID Control Point</item><item uuid="0x2A4D">Report</item><item uuid="0x2A4E">Protocol Mode</item><item uuid="0x2A4F">Scan Interval Window</item><item uuid="0x2A50">PnP ID</item><item uuid="0x2A51">Glucose Feature</item><item uuid="0x2A52">Record Access Control Point</item></group>\r
+    <group>Services<item uuid="0x1800">Generic Access Service</item><item uuid="0x1801">Generic Attribute Service</item><item uuid="0x1802">Immediate Alert Service</item><item uuid="0x1803">Link Loss Service</item><item uuid="0x1804">Tx Power Service</item><item uuid="0x1805">Current Time Service</item><item uuid="0x1806">Reference Time Update Service</item><item uuid="0x1807">Next DST Change Service</item><item uuid="0x1808">Glucose Service</item><item uuid="0x1809">Health Thermometer Service</item><item uuid="0x180A">Device Information Service</item><item uuid="0x180D">Heart Rate Service</item><item uuid="0x180E">Phone Alert Status Service</item><item uuid="0x180F">Battery Service</item><item uuid="0x1810">Blood Pressure Service</item><item uuid="0x1811">Alert Notification Service</item><item uuid="0x1812">Human Interface Device Service</item><item uuid="0x1813">Scan Parameters Service</item></group>\r
+    <group>Declarations<item uuid="0x2800">GATT Primary Service Declaration</item><item uuid="0x2801">GATT Secondary Service Declaration</item><item uuid="0x2802">GATT Include Declaration</item><item uuid="0x2803">GATT Characteristic Declaration</item></group>\r
+  </profile>\r
+  <profile>\r
+    <name>Sensor Tag</name>\r
+    <item uuid="0xAA00">IR Temperature Service</item>\r
+    <item uuid="0xAA01" descr="ObjectLSB:ObjectMSB:AmbientLSB:AmbientMSB">IR Temperature Data</item>\r
+    <item uuid="0xAA02" descr="Write &quot;01&quot; to start Sensor and Measurements, &quot;00&quot; to put to sleep">IR Temperature Config</item>\r
+    <item uuid="0xAA03" descr="Period = [Input*10] ms, (lower limit 300 ms), default 1000 ms">IR Temperature Period</item>\r
+    <item uuid="0xAA10">Accelerometer Service</item>\r
+    <item uuid="0xAA11" descr="X : Y : Z Coordinates">Accelerometer Data</item>\r
+    <item uuid="0xAA12" descr="Write &quot;01&quot; to select range 2G, &quot;02&quot; for 4G, &quot;03&quot; for 8G, &quot;00&quot; disable sensor">Accelerometer Config</item>\r
+    <item uuid="0xAA13" descr="Period = [Input*10] ms, (lower limit 100ms), default 1000 ms">Accelerometer Period</item>\r
+    <item uuid="0xAA20">Humidity Service</item>\r
+    <item uuid="0xAA21" descr="TempLSB:TempMSB:HumidityLSB:HumidityMSB">Humidity Data</item>\r
+    <item uuid="0xAA22" descr="Write &quot;01&quot; to start measurements, &quot;00&quot; to stop">Humidity Config</item>\r
+    <item uuid="0xAA23" descr="Period = [Input*10] ms, (lower limit 100 ms), default 1000 ms">Humidity Period</item>\r
+    <item uuid="0xAA30">Magnetometer Service</item>\r
+    <item uuid="0xAA31" descr="XLSB:XMSB:YLSB:YMSB: ZLSB:ZMSB Coordinates">Magnetometer Data</item>\r
+    <item uuid="0xAA32" descr="Write &quot;01&quot; to start Sensor and Measurements, &quot;00&quot; to put to sleep">Magnetometer Config</item>\r
+    <item uuid="0xAA33" descr="Period = [Input*10]ms (lower limit 100ms), default 2000ms">Magnetometer Period</item>\r
+    <item uuid="0xAA40">Barometer Service</item>\r
+    <item uuid="0xAA41" descr="TempLSB:TempMSB:PressureLSB:PressureMSB">Barometer Data</item>\r
+    <item uuid="0xAA42" descr="Write &quot;01&quot; to start Sensor and Measurements, &quot;00&quot; to put to sleep, &quot;02&quot; to read calibration values from sensor">Barometer Configuration</item>\r
+    <item descr="When write &quot;02&quot; to Barometer conf. has been issued, the calibration values is found here." uuid="0xAA43">Barometer Calibration</item>\r
+    <item uuid="0xAA44" descr="Period = [Input*10] ms, (lower limit 100 ms), default 1000 ms">Barometer Period</item>\r
+    <item uuid="0xAA50">Gyroscope Service</item>\r
+    <item uuid="0xAA51" descr="XLSB:XMSB:YLSB:YMSB: ZLSB:ZMSB">Gyroscope Data</item>\r
+    <item uuid="0xAA52" descr="Write 0 to turn off gyroscope, 1 to enable X axis only, 2 to enable Y axis only, 3 = X and Y, 4 = Z only, 5 = X and Z, 6 = Y and Z, 7 = X, Y and Z">Gyroscope Config</item>\r
+    <item uuid="0xAA53" descr="Period = [Input*10]ms (lower limit 100ms), default 2000ms">Gyroscope Period</item>\r
+    <item uuid="0xAA60">Test Service</item>\r
+    <item uuid="0xAA61" descr="Self-test results (high bit indicates PASSED): Bit 0:IR temp, 1:Humidity, 2:Magnetometer, 3:accelerometer, 4:Barometer, 5:Gyroscope">Test Data</item>\r
+    <item uuid="0xAA62" descr="bit 7: enable test mode; bit 0-1 LED bit mask">Test Config</item>\r
+    <item uuid="0xCCC0">Connection Control Service</item>\r
+    <item uuid="0xCCC1" descr="ConnInterval,SlaveLatency,SupervisionTimeout (2 bytes each)">Connection Parameters</item>\r
+    <item uuid="0xCCC2" descr="MinConnInterval,MaxConnInterval,SlaveLatency,SupervisionTimeout (2 bytes each)">Request Connection Parameters</item>\r
+    <item uuid="0xCCC3" descr="Change the value to disconnect">Disconnect request</item>\r
+  </profile>\r
+  <profile>\r
+    <name>Poly Tag</name>\r
+    <item uuid="0xAD10">Accelerometer Service</item>\r
+    <item uuid="0xAD11" descr="X : Y : Z Coordinates">Accelerometer Data</item>\r
+    <item uuid="0xAD12" descr="Write &quot;01&quot; to start Sensor and Measurements, &quot;00&quot; to put to sleep">Accelerometer Config</item>\r
+    <item uuid="0xAD13" descr="Period = [Input*10] ms, (lower limit 100ms), default 1000 ms">Accelerometer Period</item>\r
+    <item uuid="0xAD20">Polypower Service</item>\r
+    <item uuid="0xAD21">Polypower Data</item>\r
+    <item uuid="0xAD22" descr="Set bit 0 to enable input 0 etc. Write 0 to disable all inputs, 1F to enable all.">Polypower Config</item>\r
+    <item uuid="0xAD23" descr="Period = [Input*10] ms (range 100-1000 ms, default 250 ms)">Polypower Period</item>\r
+    <item uuid="0xAD24" descr="Threshold (raw unsigned 16-bit hex). Samples below this value are ignored.">Polypower Threshold</item>\r
+    <item uuid="0xAD30">Test Service</item>\r
+    <item uuid="0xAD31" descr="Self-test results (high bit indicates PASSED) 0:Accelerometer, 1:Polypower">Test Data</item>\r
+    <item uuid="0xAD32" descr="bit 7: enable test mode; bit 0 controls LED">Test Config</item>\r
+  </profile>\r
+  <profile>\r
+    <name>Accelerometer</name>\r
+    <item uuid="0xFFA0">Accelerometer Service</item>\r
+    <item uuid="0xFFA1" descr="Write &quot;01&quot; to enable, &quot;00&quot; to disable">Accererometer enable</item>\r
+    <item uuid="0xFFA2" descr="Range: 20=2G, 80=8G">Accelerometer range</item>\r
+    <item uuid="0xFFA3">Accelerometer X-coordinate</item>\r
+    <item uuid="0xFFA4">Accelerometer Y-coordinate</item>\r
+    <item uuid="0xFFA5">Accelerometer Z-coordinate</item>\r
+  </profile>\r
+  <profile>\r
+    <name>Simple Keys</name>\r
+    <item uuid="0xFFE0">Simple Keys Service</item>\r
+    <item uuid="0xFFE1">Key press state</item>\r
+  </profile>\r
+  <profile>\r
+    <name>Racing Car</name>\r
+    <item uuid="0xACC0">Racing Car Service</item>\r
+    <item uuid="0xACC1" descr="Range: 0xCE .. 0x32">Throttle</item>\r
+    <item uuid="0xACC2" descr="Range: 0xCE .. 0x32">Steering</item>\r
+    <item uuid="0xACC3" descr="Not implemented">Lights/Horn</item>\r
+  </profile>\r
+  <profile>\r
+    <name>OAD</name>\r
+    <item uuid="0xFFC0">OAD Service</item>\r
+    <item uuid="0xFFC1">OAD Image Identify</item>\r
+    <item uuid="0xFFC2">OAD Image Block</item>\r
+  </profile>\r
+  <profile>\r
+    <name>Simple BLE Peripheral</name>\r
+    <item uuid="0xFFF0">Simple Profile Service</item>\r
+    <item uuid="0xFFF1">Simple Profile Characteristic 1</item>\r
+    <item uuid="0xFFF2">Simple Profile Characteristic 2</item>\r
+    <item uuid="0xFFF3">Simple Profile Characteristic 3</item>\r
+    <item uuid="0xFFF4">Simple Profile Characteristic 4</item>\r
+    <item uuid="0xFFF5">Simple Profile Characteristic 5</item>\r
+  </profile>\r
+</gattuuid>
\ No newline at end of file
diff --git a/res/xml/list_gradient.xml b/res/xml/list_gradient.xml
new file mode 100644 (file)
index 0000000..2e02bf0
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/list_item_normal" />
+
+</selector>
\ No newline at end of file
diff --git a/res/xml/popup.xml b/res/xml/popup.xml
new file mode 100644 (file)
index 0000000..adba2dd
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:keyWidth="10%p"\r
+    android:keyHeight="10%p">\r
+</Keyboard>
\ No newline at end of file
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
new file mode 100644 (file)
index 0000000..b059584
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:example="http://schemas.android.com/apk/res/com.ti.sensortag" >\r
+    \r
+    <PreferenceCategory android:title="Sensors online" >\r
+        \r
+        <!-- \r
+               Checkboxes have keys that match (with a simple transformation) the enum names in Sensor.java for easy\r
+               decoding/encoding between java code and xml. \r
+        -->\r
+        <CheckBoxPreference\r
+            android:key="pref_simple_keys_on"\r
+            android:summary="Turn the Simple keys service on or off."\r
+            android:defaultValue="true"\r
+            android:persistent="true"\r
+            android:title="Buttons" />\r
+        <CheckBoxPreference\r
+            android:key="pref_accelerometer_on"\r
+            android:summary="Turn the Accelerometer service on or off."\r
+            android:defaultValue="true"\r
+            android:persistent="true"\r
+            android:title="Accelerometer" />\r
+        <CheckBoxPreference\r
+            android:key="pref_magnetometer_on"\r
+            android:summary="Turn the Magnetometer service on or off."\r
+            android:defaultValue="true"\r
+            android:persistent="true"\r
+            android:title="Magnetometer" />\r
+        <CheckBoxPreference\r
+            android:key="pref_gyroscope_on"\r
+            android:summary="Turn the Gyroscope service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="Gyroscope" />\r
+        <CheckBoxPreference\r
+            android:key="pref_ir_temperature_on"\r
+            android:summary="Turn the IR and Ambient Temperature service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="IR and Ambient Temperature" />\r
+        <CheckBoxPreference\r
+            android:key="pref_humidity_on"\r
+            android:summary="Turn the Humidity service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="Humidity" />\r
+        <CheckBoxPreference\r
+            android:key="pref_barometer_on"\r
+            android:summary="Turn the Barometer service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="Barometer" />\r
+    </PreferenceCategory>\r
+    \r
+</PreferenceScreen>\r
diff --git a/res/xml/preferences2.xml b/res/xml/preferences2.xml
new file mode 100644 (file)
index 0000000..9400812
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:example="http://schemas.android.com/apk/res/com.ti.sensortag" >\r
+    \r
+    <PreferenceCategory android:title="Sensors online" >\r
+        \r
+        <!-- \r
+               Checkboxes have keys that match (with a simple transformation) the enum names in Sensor.java for easy\r
+               decoding/encoding between java code and xml. \r
+        -->\r
+        <CheckBoxPreference\r
+            android:key="pref_simple_keys_on"\r
+            android:summary="Turn the Simple keys service on or off."\r
+            android:defaultValue="true"\r
+            android:persistent="true"\r
+            android:title="Buttons" />\r
+        <CheckBoxPreference\r
+            android:key="pref_accelerometer_on"\r
+            android:summary="Turn the Accelerometer service on or off."\r
+            android:defaultValue="true"\r
+            android:persistent="true"\r
+            android:title="Accelerometer" />\r
+        <CheckBoxPreference\r
+            android:key="pref_luxometer_on"\r
+            android:summary="Turn the Luxometer service on or off."\r
+            android:defaultValue="true"\r
+            android:persistent="true"\r
+            android:title="Luxometer" />\r
+        <CheckBoxPreference\r
+            android:key="pref_gyroscope_on"\r
+            android:summary="Turn the Gyroscope service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="Gyroscope" />\r
+        <CheckBoxPreference\r
+            android:key="pref_ir_temperature_on"\r
+            android:summary="Turn the IR and Ambient Temperature service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="IR and Ambient Temperature" />\r
+        <CheckBoxPreference\r
+            android:key="pref_humidity_on"\r
+            android:summary="Turn the Humidity service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="Humidity" />\r
+        <CheckBoxPreference\r
+            android:key="pref_barometer_on"\r
+            android:summary="Turn the Barometer service on or off."\r
+            android:defaultValue="false"\r
+            android:persistent="true"\r
+            android:title="Barometer" />\r
+    </PreferenceCategory>\r
+    \r
+</PreferenceScreen>\r
diff --git a/src/com/example/ti/ble/common/BleDeviceInfo.java b/src/com/example/ti/ble/common/BleDeviceInfo.java
new file mode 100644 (file)
index 0000000..ca4e486
--- /dev/null
@@ -0,0 +1,81 @@
+/**************************************************************************************************\r
+  Filename:       BleDeviceInfo.java\r
+  Revised:        $Date: 2013-08-30 12:08:11 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27477 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.common;\r
+\r
+import android.bluetooth.BluetoothDevice;\r
+\r
+public class BleDeviceInfo {\r
+  // Data\r
+  private BluetoothDevice mBtDevice;\r
+  private int mRssi;\r
+\r
+  public BleDeviceInfo(BluetoothDevice device, int rssi) {\r
+    mBtDevice = device;\r
+    mRssi = rssi;\r
+  }\r
+\r
+  public BluetoothDevice getBluetoothDevice() {\r
+    return mBtDevice;\r
+  }\r
+\r
+  public int getRssi() {\r
+    return mRssi;\r
+  }\r
+\r
+  public void updateRssi(int rssiValue) {\r
+    mRssi = rssiValue;\r
+  }\r
+\r
+}\r
diff --git a/src/com/example/ti/ble/common/BluetoothLeService.java b/src/com/example/ti/ble/common/BluetoothLeService.java
new file mode 100644 (file)
index 0000000..896c0a4
--- /dev/null
@@ -0,0 +1,548 @@
+/**************************************************************************************************\r
+  Filename:       BluetoothLeService.java\r
+  Revised:        $Date: 2013-09-09 16:23:36 +0200 (ma, 09 sep 2013) $\r
+  Revision:       $Revision: 27674 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.common;\r
+\r
+import java.util.List;\r
+import android.app.Service;\r
+import android.bluetooth.BluetoothAdapter;\r
+import android.bluetooth.BluetoothDevice;\r
+import android.bluetooth.BluetoothGatt;\r
+import android.bluetooth.BluetoothGattCallback;\r
+import android.bluetooth.BluetoothGattCharacteristic;\r
+import android.bluetooth.BluetoothGattDescriptor;\r
+import android.bluetooth.BluetoothGattService;\r
+import android.bluetooth.BluetoothManager;\r
+import android.bluetooth.BluetoothProfile;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.os.Binder;\r
+import android.os.IBinder;\r
+\r
+// import android.util.Log;\r
+\r
+/**\r
+ * Service for managing connection and data communication with a GATT server\r
+ * hosted on a given Bluetooth LE device.\r
+ */\r
+public class BluetoothLeService extends Service {\r
+       static final String TAG = "BluetoothLeService";\r
+\r
+       public final static String ACTION_GATT_CONNECTED = "com.example.ti.ble.common.ACTION_GATT_CONNECTED";\r
+       public final static String ACTION_GATT_DISCONNECTED = "com.example.ti.ble.common.ACTION_GATT_DISCONNECTED";\r
+       public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.ti.ble.common.ACTION_GATT_SERVICES_DISCOVERED";\r
+       public final static String ACTION_DATA_READ = "com.example.ti.ble.common.ACTION_DATA_READ";\r
+       public final static String ACTION_DATA_NOTIFY = "com.example.ti.ble.common.ACTION_DATA_NOTIFY";\r
+       public final static String ACTION_DATA_WRITE = "com.example.ti.ble.common.ACTION_DATA_WRITE";\r
+       public final static String EXTRA_DATA = "com.example.ti.ble.common.EXTRA_DATA";\r
+       public final static String EXTRA_UUID = "com.example.ti.ble.common.EXTRA_UUID";\r
+       public final static String EXTRA_STATUS = "com.example.ti.ble.common.EXTRA_STATUS";\r
+       public final static String EXTRA_ADDRESS = "com.example.ti.ble.common.EXTRA_ADDRESS";\r
+\r
+       // BLE\r
+       private BluetoothManager mBluetoothManager = null;\r
+       private BluetoothAdapter mBtAdapter = null;\r
+       private BluetoothGatt mBluetoothGatt = null;\r
+       private static BluetoothLeService mThis = null;\r
+       private volatile boolean mBusy = false; // Write/read pending response\r
+       private String mBluetoothDeviceAddress;\r
+\r
+       /**\r
+        * GATT client callbacks\r
+        */\r
+       private BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {\r
+\r
+               @Override\r
+               public void onConnectionStateChange(BluetoothGatt gatt, int status,\r
+                   int newState) {\r
+                       if (mBluetoothGatt == null) {\r
+                               // Log.e(TAG, "mBluetoothGatt not created!");\r
+                               return;\r
+                       }\r
+\r
+                       BluetoothDevice device = gatt.getDevice();\r
+                       String address = device.getAddress();\r
+                       // Log.d(TAG, "onConnectionStateChange (" + address + ") " + newState +\r
+                       // " status: " + status);\r
+\r
+                       try {\r
+                               switch (newState) {\r
+                               case BluetoothProfile.STATE_CONNECTED:\r
+                                       broadcastUpdate(ACTION_GATT_CONNECTED, address, status);\r
+                                       break;\r
+                               case BluetoothProfile.STATE_DISCONNECTED:\r
+                                       broadcastUpdate(ACTION_GATT_DISCONNECTED, address, status);\r
+                                       break;\r
+                               default:\r
+                                       // Log.e(TAG, "New state not processed: " + newState);\r
+                                       break;\r
+                               }\r
+                       } catch (NullPointerException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+\r
+               @Override\r
+               public void onServicesDiscovered(BluetoothGatt gatt, int status) {\r
+                       BluetoothDevice device = gatt.getDevice();\r
+                       broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED, device.getAddress(),\r
+                           status);\r
+               }\r
+\r
+               @Override\r
+               public void onCharacteristicChanged(BluetoothGatt gatt,\r
+                   BluetoothGattCharacteristic characteristic) {\r
+                       broadcastUpdate(ACTION_DATA_NOTIFY, characteristic,\r
+                           BluetoothGatt.GATT_SUCCESS);\r
+               }\r
+\r
+               @Override\r
+               public void onCharacteristicRead(BluetoothGatt gatt,\r
+                   BluetoothGattCharacteristic characteristic, int status) {\r
+                       broadcastUpdate(ACTION_DATA_READ, characteristic, status);\r
+               }\r
+\r
+               @Override\r
+               public void onCharacteristicWrite(BluetoothGatt gatt,\r
+                   BluetoothGattCharacteristic characteristic, int status) {\r
+                       broadcastUpdate(ACTION_DATA_WRITE, characteristic, status);\r
+               }\r
+\r
+               @Override\r
+               public void onDescriptorRead(BluetoothGatt gatt,\r
+                   BluetoothGattDescriptor descriptor, int status) {\r
+                       mBusy = false;\r
+               }\r
+\r
+               @Override\r
+               public void onDescriptorWrite(BluetoothGatt gatt,\r
+                   BluetoothGattDescriptor descriptor, int status) {\r
+                       // Log.i(TAG, "onDescriptorWrite: " + descriptor.getUuid().toString());\r
+                       mBusy = false;\r
+               }\r
+       };\r
+\r
+       private void broadcastUpdate(final String action, final String address,\r
+           final int status) {\r
+               final Intent intent = new Intent(action);\r
+               intent.putExtra(EXTRA_ADDRESS, address);\r
+               intent.putExtra(EXTRA_STATUS, status);\r
+               sendBroadcast(intent);\r
+               mBusy = false;\r
+       }\r
+\r
+       private void broadcastUpdate(final String action,\r
+           final BluetoothGattCharacteristic characteristic, final int status) {\r
+               final Intent intent = new Intent(action);\r
+               intent.putExtra(EXTRA_UUID, characteristic.getUuid().toString());\r
+               intent.putExtra(EXTRA_DATA, characteristic.getValue());\r
+               intent.putExtra(EXTRA_STATUS, status);\r
+               sendBroadcast(intent);\r
+               mBusy = false;\r
+       }\r
+\r
+       private boolean checkGatt() {\r
+               if (mBtAdapter == null) {\r
+                       // Log.w(TAG, "BluetoothAdapter not initialized");\r
+                       return false;\r
+               }\r
+               if (mBluetoothGatt == null) {\r
+                       // Log.w(TAG, "BluetoothGatt not initialized");\r
+                       return false;\r
+               }\r
+\r
+               if (mBusy) {\r
+                       // Log.w(TAG, "LeService busy");\r
+                       return false;\r
+               }\r
+               return true;\r
+\r
+       }\r
+\r
+       /**\r
+        * Manage the BLE service\r
+        */\r
+       public class LocalBinder extends Binder {\r
+               public BluetoothLeService getService() {\r
+                       return BluetoothLeService.this;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public IBinder onBind(Intent intent) {\r
+               return binder;\r
+       }\r
+\r
+       @Override\r
+       public boolean onUnbind(Intent intent) {\r
+               // After using a given device, you should make sure that\r
+               // BluetoothGatt.close() is called\r
+               // such that resources are cleaned up properly. In this particular example,\r
+               // close() is\r
+               // invoked when the UI is disconnected from the Service.\r
+               close();\r
+               return super.onUnbind(intent);\r
+       }\r
+\r
+       private final IBinder binder = new LocalBinder();\r
+\r
+       /**\r
+        * Initializes a reference to the local Bluetooth adapter.\r
+        * \r
+        * @return Return true if the initialization is successful.\r
+        */\r
+       public boolean initialize() {\r
+               // For API level 18 and above, get a reference to BluetoothAdapter through\r
+               // BluetoothManager.\r
+               mThis = this;\r
+               if (mBluetoothManager == null) {\r
+                       mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\r
+                       if (mBluetoothManager == null) {\r
+                               // Log.e(TAG, "Unable to initialize BluetoothManager.");\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+               mBtAdapter = mBluetoothManager.getAdapter();\r
+               if (mBtAdapter == null) {\r
+                       // Log.e(TAG, "Unable to obtain a BluetoothAdapter.");\r
+                       return false;\r
+               }\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public int onStartCommand(Intent intent, int flags, int startId) {\r
+               // Log.i(TAG, "Received start id " + startId + ": " + intent);\r
+               // We want this service to continue running until it is explicitly\r
+               // stopped, so return sticky.\r
+               return START_STICKY;\r
+       }\r
+\r
+       @Override\r
+       public void onDestroy() {\r
+               super.onDestroy();\r
+               if (mBluetoothGatt != null) {\r
+                       mBluetoothGatt.close();\r
+                       mBluetoothGatt = null;\r
+               }\r
+       }\r
+\r
+       //\r
+       // GATT API\r
+       //\r
+       /**\r
+        * Request a read on a given {@code BluetoothGattCharacteristic}. The read\r
+        * result is reported asynchronously through the\r
+        * {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}\r
+        * callback.\r
+        * \r
+        * @param characteristic\r
+        *          The characteristic to read from.\r
+        */\r
+       public void readCharacteristic(BluetoothGattCharacteristic characteristic) {\r
+               if (!checkGatt())\r
+                       return;\r
+               mBusy = true;\r
+               mBluetoothGatt.readCharacteristic(characteristic);\r
+       }\r
+\r
+       public boolean writeCharacteristic(\r
+           BluetoothGattCharacteristic characteristic, byte b) {\r
+               if (!checkGatt())\r
+                       return false;\r
+\r
+               byte[] val = new byte[1];\r
+               val[0] = b;\r
+               characteristic.setValue(val);\r
+\r
+               mBusy = true;\r
+               return mBluetoothGatt.writeCharacteristic(characteristic);\r
+       }\r
+\r
+       public boolean writeCharacteristic(\r
+           BluetoothGattCharacteristic characteristic, boolean b) {\r
+               if (!checkGatt())\r
+                       return false;\r
+\r
+               byte[] val = new byte[1];\r
+\r
+               val[0] = (byte) (b ? 1 : 0);\r
+               characteristic.setValue(val);\r
+               mBusy = true;\r
+               return mBluetoothGatt.writeCharacteristic(characteristic);\r
+       }\r
+\r
+       public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {\r
+               if (!checkGatt())\r
+                       return false;\r
+\r
+               mBusy = true;\r
+               return mBluetoothGatt.writeCharacteristic(characteristic);\r
+       }\r
+\r
+       /**\r
+        * Retrieves the number of GATT services on the connected device. This should\r
+        * be invoked only after {@code BluetoothGatt#discoverServices()} completes\r
+        * successfully.\r
+        * \r
+        * @return A {@code integer} number of supported services.\r
+        */\r
+       public int getNumServices() {\r
+               if (mBluetoothGatt == null)\r
+                       return 0;\r
+\r
+               return mBluetoothGatt.getServices().size();\r
+       }\r
+\r
+       /**\r
+        * Retrieves a list of supported GATT services on the connected device. This\r
+        * should be invoked only after {@code BluetoothGatt#discoverServices()}\r
+        * completes successfully.\r
+        * \r
+        * @return A {@code List} of supported services.\r
+        */\r
+       public List<BluetoothGattService> getSupportedGattServices() {\r
+               if (mBluetoothGatt == null)\r
+                       return null;\r
+\r
+               return mBluetoothGatt.getServices();\r
+       }\r
+\r
+       /**\r
+        * Enables or disables notification on a give characteristic.\r
+        * \r
+        * @param characteristic\r
+        *          Characteristic to act on.\r
+        * @param enabled\r
+        *          If true, enable notification. False otherwise.\r
+        */\r
+       public boolean setCharacteristicNotification(\r
+           BluetoothGattCharacteristic characteristic, boolean enable) {\r
+               if (!checkGatt())\r
+                       return false;\r
+\r
+               boolean ok = false;\r
+               if (mBluetoothGatt.setCharacteristicNotification(characteristic, enable)) {\r
+\r
+                       BluetoothGattDescriptor clientConfig = characteristic\r
+                           .getDescriptor(GattInfo.CLIENT_CHARACTERISTIC_CONFIG);\r
+                       if (clientConfig != null) {\r
+\r
+                               if (enable) {\r
+                                       // Log.i(TAG, "Enable notification: " +\r
+                                       // characteristic.getUuid().toString());\r
+                                       ok = clientConfig\r
+                                           .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);\r
+                               } else {\r
+                                       // Log.i(TAG, "Disable notification: " +\r
+                                       // characteristic.getUuid().toString());\r
+                                       ok = clientConfig\r
+                                           .setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);\r
+                               }\r
+\r
+                               if (ok) {\r
+                                       mBusy = true;\r
+                                       ok = mBluetoothGatt.writeDescriptor(clientConfig);\r
+                                       // Log.i(TAG, "writeDescriptor: " +\r
+                                       // characteristic.getUuid().toString());\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return ok;\r
+       }\r
+\r
+       public boolean isNotificationEnabled(\r
+           BluetoothGattCharacteristic characteristic) {\r
+               if (!checkGatt())\r
+                       return false;\r
+\r
+               BluetoothGattDescriptor clientConfig = characteristic\r
+                   .getDescriptor(GattInfo.CLIENT_CHARACTERISTIC_CONFIG);\r
+               if (clientConfig == null)\r
+                       return false;\r
+\r
+               return clientConfig.getValue() == BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;\r
+       }\r
+\r
+       /**\r
+        * Connects to the GATT server hosted on the Bluetooth LE device.\r
+        * \r
+        * @param address\r
+        *          The device address of the destination device.\r
+        * \r
+        * @return Return true if the connection is initiated successfully. The\r
+        *         connection result is reported asynchronously through the\r
+        *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}\r
+        *         callback.\r
+        */\r
+       public boolean connect(final String address) {\r
+               if (mBtAdapter == null || address == null) {\r
+                       // Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");\r
+                       return false;\r
+               }\r
+               final BluetoothDevice device = mBtAdapter.getRemoteDevice(address);\r
+               int connectionState = mBluetoothManager.getConnectionState(device,\r
+                   BluetoothProfile.GATT);\r
+\r
+               if (connectionState == BluetoothProfile.STATE_DISCONNECTED) {\r
+\r
+                       // Previously connected device. Try to reconnect.\r
+                       if (mBluetoothDeviceAddress != null\r
+                           && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {\r
+                               // Log.d(TAG, "Re-use GATT connection");\r
+                               if (mBluetoothGatt.connect()) {\r
+                                       return true;\r
+                               } else {\r
+                                       // Log.w(TAG, "GATT re-connect failed.");\r
+                                       return false;\r
+                               }\r
+                       }\r
+\r
+                       if (device == null) {\r
+                               // Log.w(TAG, "Device not found.  Unable to connect.");\r
+                               return false;\r
+                       }\r
+                       // We want to directly connect to the device, so we are setting the\r
+                       // autoConnect parameter to false.\r
+                       // Log.d(TAG, "Create a new GATT connection.");\r
+                       mBluetoothGatt = device.connectGatt(this, false, mGattCallbacks);\r
+                       mBluetoothDeviceAddress = address;\r
+               } else {\r
+                       // Log.w(TAG, "Attempt to connect in state: " + connectionState);\r
+                       return false;\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Disconnects an existing connection or cancel a pending connection. The\r
+        * disconnection result is reported asynchronously through the\r
+        * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}\r
+        * callback.\r
+        */\r
+       public void disconnect(String address) {\r
+               if (mBtAdapter == null) {\r
+                       // Log.w(TAG, "disconnect: BluetoothAdapter not initialized");\r
+                       return;\r
+               }\r
+               final BluetoothDevice device = mBtAdapter.getRemoteDevice(address);\r
+               int connectionState = mBluetoothManager.getConnectionState(device,\r
+                   BluetoothProfile.GATT);\r
+\r
+               if (mBluetoothGatt != null) {\r
+                       if (connectionState != BluetoothProfile.STATE_DISCONNECTED) {\r
+                               mBluetoothGatt.disconnect();\r
+                       } else {\r
+                               // Log.w(TAG, "Attempt to disconnect in state: " + connectionState);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * After using a given BLE device, the app must call this method to ensure\r
+        * resources are released properly.\r
+        */\r
+       public void close() {\r
+               if (mBluetoothGatt != null) {\r
+                       // Log.i(TAG, "close");\r
+                       mBluetoothGatt.close();\r
+                       mBluetoothGatt = null;\r
+               }\r
+  }\r
+\r
+       public int numConnectedDevices() {\r
+               int n = 0;\r
+\r
+               if (mBluetoothGatt != null) {\r
+                       List<BluetoothDevice> devList;\r
+                       devList = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);\r
+                       n = devList.size();\r
+               }\r
+               return n;\r
+       }\r
+\r
+       //\r
+       // Utility functions\r
+       //\r
+       public static BluetoothGatt getBtGatt() {\r
+               return mThis.mBluetoothGatt;\r
+       }\r
+\r
+       public static BluetoothManager getBtManager() {\r
+               return mThis.mBluetoothManager;\r
+       }\r
+\r
+       public static BluetoothLeService getInstance() {\r
+               return mThis;\r
+       }\r
+\r
+       public boolean waitIdle(int timeout) {\r
+               timeout /= 10;\r
+               while (--timeout > 0) {\r
+                       if (mBusy)\r
+                               try {\r
+                                       Thread.sleep(10);\r
+                               } catch (InterruptedException e) {\r
+                                       e.printStackTrace();\r
+                               }\r
+                       else\r
+                               break;\r
+               }\r
+\r
+               return timeout > 0;\r
+       }\r
+\r
+}\r
diff --git a/src/com/example/ti/ble/common/GattInfo.java b/src/com/example/ti/ble/common/GattInfo.java
new file mode 100644 (file)
index 0000000..10036d7
--- /dev/null
@@ -0,0 +1,162 @@
+/**************************************************************************************************\r
+  Filename:       GattInfo.java\r
+  Revised:        $Date: 2013-08-30 12:02:37 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27470 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.common;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.UUID;\r
+\r
+import org.xmlpull.v1.XmlPullParser;\r
+import org.xmlpull.v1.XmlPullParserException;\r
+\r
+import android.content.res.XmlResourceParser;\r
+\r
+public class GattInfo {\r
+  // Bluetooth SIG identifiers\r
+  public static final UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");\r
+  private static final String uuidBtSigBase = "0000****-0000-1000-8000-00805f9b34fb";\r
+  private static final String uuidTiBase = "f000****-0451-4000-b000-000000000000";\r
+\r
+  public static final UUID OAD_SERVICE_UUID = UUID.fromString("f000ffc0-0451-4000-b000-000000000000");\r
+  public static final UUID CC_SERVICE_UUID = UUID.fromString("f000ccc0-0451-4000-b000-000000000000");\r
+\r
+  private static Map<String, String> mNameMap = new HashMap<String, String>();\r
+  private static Map<String, String> mDescrMap = new HashMap<String, String>();\r
+\r
+  public GattInfo(XmlResourceParser xpp) {\r
+    // XML data base\r
+    try {\r
+      readUuidData(xpp);\r
+    } catch (XmlPullParserException e) {\r
+      e.printStackTrace();\r
+    } catch (IOException e) {\r
+      e.printStackTrace();\r
+    }\r
+  }\r
+\r
+  public static String uuidToName(UUID uuid) {\r
+    String str = toShortUuidStr(uuid);\r
+    return uuidToName(str.toUpperCase());\r
+  }\r
+\r
+  public static String getDescription(UUID uuid) {\r
+    String str = toShortUuidStr(uuid);\r
+    return mDescrMap.get(str.toUpperCase());\r
+  }\r
+\r
+  static public boolean isTiUuid(UUID u) {\r
+    String us = u.toString();\r
+    String r = toShortUuidStr(u);\r
+    us = us.replace(r, "****");\r
+    return us.equals(uuidTiBase);\r
+  }\r
+\r
+  static public boolean isBtSigUuid(UUID u) {\r
+    String us = u.toString();\r
+    String r = toShortUuidStr(u);\r
+    us = us.replace(r, "****");\r
+    return us.equals(uuidBtSigBase);\r
+  }\r
+\r
+  static public String uuidToString(UUID u) {\r
+    String uuidStr;\r
+    if (isBtSigUuid(u))\r
+      uuidStr = GattInfo.toShortUuidStr(u);\r
+    else\r
+      uuidStr = u.toString();\r
+    return uuidStr.toUpperCase();\r
+  }\r
+\r
+  static private String toShortUuidStr(UUID u) {\r
+    return u.toString().substring(4, 8);\r
+  }\r
+\r
+  private static String uuidToName(String uuidStr16) {\r
+    return mNameMap.get(uuidStr16);\r
+  }\r
+\r
+  //\r
+  // XML loader\r
+  //\r
+  private void readUuidData(XmlResourceParser xpp) throws XmlPullParserException, IOException {\r
+    xpp.next();\r
+    String tagName = null;\r
+    String uuid = null;\r
+    String descr = null;\r
+    int eventType = xpp.getEventType();\r
+\r
+    while (eventType != XmlPullParser.END_DOCUMENT) {\r
+      if (eventType == XmlPullParser.START_DOCUMENT) {\r
+        // do nothing\r
+      } else if (eventType == XmlPullParser.START_TAG) {\r
+        tagName = xpp.getName();\r
+        uuid = xpp.getAttributeValue(null, "uuid");\r
+        descr = xpp.getAttributeValue(null, "descr");\r
+      } else if (eventType == XmlPullParser.END_TAG) {\r
+        // do nothing\r
+      } else if (eventType == XmlPullParser.TEXT) {\r
+        if (tagName.equalsIgnoreCase("item")) {\r
+          if (!uuid.isEmpty()) {\r
+            uuid = uuid.replace("0x", "");\r
+            mNameMap.put(uuid, xpp.getText());\r
+            mDescrMap.put(uuid, descr);\r
+          }\r
+        }\r
+      }\r
+      eventType = xpp.next();\r
+    }\r
+  }\r
+}\r
diff --git a/src/com/example/ti/ble/common/HelpView.java b/src/com/example/ti/ble/common/HelpView.java
new file mode 100644 (file)
index 0000000..adb17a9
--- /dev/null
@@ -0,0 +1,89 @@
+/**************************************************************************************************\r
+  Filename:       HelpView.java\r
+  Revised:        $Date: 2013-08-30 12:02:37 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27470 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.common;\r
+\r
+import android.os.Bundle;\r
+import android.support.v4.app.Fragment;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.webkit.WebView;\r
+\r
+public class HelpView extends Fragment {\r
+  private String mFile = "about.html";\r
+  private int mIdFragment;\r
+  private int mIdWebPage;\r
+\r
+  public HelpView() {\r
+       \r
+  }\r
+  \r
+  public void setParameters(String file, int idFragment, int idWebPage) {\r
+    if (file != null)\r
+      mFile = file;\r
+    mIdFragment = idFragment;\r
+    mIdWebPage = idWebPage;\r
+  }\r
+\r
+  @Override\r
+  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
+    View rootView = inflater.inflate(mIdFragment, container, false);\r
+    WebView wv = (WebView) rootView.findViewById(mIdWebPage);\r
+\r
+    wv.loadUrl("file:///android_asset/" + mFile);\r
+    return rootView;\r
+  }\r
+\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/AboutDialog.java b/src/com/example/ti/ble/sensortag/AboutDialog.java
new file mode 100644 (file)
index 0000000..dda6966
--- /dev/null
@@ -0,0 +1,148 @@
+/**************************************************************************************************\r
+  Filename:       AboutDialog.java\r
+  Revised:        $Date: 2013-08-30 12:02:37 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27470 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import android.app.Dialog;\r
+import android.content.Context;\r
+import android.content.pm.PackageManager.NameNotFoundException;\r
+import android.content.res.Resources;\r
+import android.os.Build;\r
+import android.os.Bundle;\r
+// import android.util.Log;\r
+import android.view.View;\r
+import android.view.Window;\r
+import android.webkit.WebView;\r
+import android.webkit.WebViewClient;\r
+import android.widget.Button;\r
+import android.widget.TextView;\r
+\r
+public class AboutDialog extends Dialog {\r
+  // Log\r
+  // private static final String TAG = "AboutDialog";\r
+\r
+  private Context mContext;\r
+  private static AboutDialog mDialog;\r
+  private static OkListener mOkListener;\r
+  private final String errorHTML = "<html><body><h1>Failed to load web page</h1></body></html>";\r
+\r
+  public AboutDialog(Context context) {\r
+    super(context);\r
+    mContext = context;\r
+    mDialog = this;\r
+    mOkListener = new OkListener();\r
+  }\r
+\r
+  @Override\r
+  public void onCreate(Bundle savedInstanceState) {\r
+    requestWindowFeature(Window.FEATURE_NO_TITLE);\r
+    setContentView(R.layout.dialog_about);\r
+\r
+    // From About.html web page\r
+    WebView webView = (WebView) findViewById(R.id.web_content);\r
+    webView.setWebViewClient(new WebViewClient(){\r
+      \r
+       @Override\r
+      public boolean shouldOverrideUrlLoading(WebView view, String url) {\r
+          view.loadUrl(url);\r
+          return false;\r
+      }\r
+      \r
+       @Override\r
+       public void onPageFinished(WebView view, final String url) {\r
+               // Log.i(TAG,"Web page loaded: " + url);\r
+       }\r
+\r
+       @Override\r
+       public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {\r
+               // Do something\r
+               view.loadData(errorHTML, "text/html", "UTF-8");\r
+               // Log.e(TAG,"Failed to load web page");\r
+       }\r
+    });\r
+\r
+    // Header\r
+    Resources res = mContext.getResources();\r
+    String appName = res.getString(R.string.app_name);\r
+    TextView title = (TextView) findViewById(R.id.title);\r
+    title.setText("About " + appName);\r
+\r
+    // Application info\r
+    TextView head = (TextView) findViewById(R.id.header);\r
+    String appVersion = "Revision: ";\r
+    try {\r
+      appVersion += mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;\r
+    } catch (NameNotFoundException e) {\r
+      // Log.v(TAG, e.getMessage());\r
+    }\r
+    head.setText(appVersion);\r
+\r
+    // Dismiss button\r
+    Button okButton = (Button) findViewById(R.id.buttonOK);\r
+    okButton.setOnClickListener(mOkListener);\r
+\r
+    // Device information\r
+    TextView foot = (TextView) findViewById(R.id.footer);\r
+    String txt = Build.MANUFACTURER.toUpperCase() + " " + Build.MODEL + " Android " + Build.VERSION.RELEASE + " " + Build.DISPLAY;\r
+\r
+    foot.setText(txt);\r
+  }\r
+\r
+  private class OkListener implements android.view.View.OnClickListener {\r
+    @Override\r
+    public void onClick(View v) {\r
+      mDialog.dismiss();\r
+    }\r
+  }\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/BarometerCalibrationCoefficients.java b/src/com/example/ti/ble/sensortag/BarometerCalibrationCoefficients.java
new file mode 100644 (file)
index 0000000..7112a4d
--- /dev/null
@@ -0,0 +1,66 @@
+/**************************************************************************************************\r
+  Filename:       BarometerCalibrationCoefficients.java\r
+  Revised:        $Date: 2013-08-30 11:44:31 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27454 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import java.util.List;\r
+\r
+/**\r
+ * As a last-second hack i'm storing the barometer coefficients in a global.\r
+ */\r
+public enum BarometerCalibrationCoefficients {\r
+  INSTANCE;\r
+  volatile public List<Integer> barometerCalibrationCoefficients;\r
+  volatile public double heightCalibration;\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/DeviceActivity.java b/src/com/example/ti/ble/sensortag/DeviceActivity.java
new file mode 100644 (file)
index 0000000..868a0dc
--- /dev/null
@@ -0,0 +1,626 @@
+/**************************************************************************************************\r
+  Filename:       DeviceActivity.java\r
+  Revised:        $Date: 2013-09-05 07:58:48 +0200 (to, 05 sep 2013) $\r
+  Revision:       $Revision: 27616 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Locale;\r
+import java.util.UUID;\r
+\r
+import android.bluetooth.BluetoothDevice;\r
+import android.bluetooth.BluetoothGatt;\r
+import android.bluetooth.BluetoothGattCharacteristic;\r
+import android.bluetooth.BluetoothGattService;\r
+import android.content.BroadcastReceiver;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.content.IntentFilter;\r
+import android.content.SharedPreferences;\r
+import android.content.res.Resources;\r
+import android.content.res.XmlResourceParser;\r
+import android.os.Build;\r
+import android.os.Bundle;\r
+import android.preference.PreferenceManager;\r
+// import android.util.Log;\r
+import android.view.Menu;\r
+import android.view.MenuInflater;\r
+import android.view.MenuItem;\r
+import android.view.View;\r
+import android.view.Window;\r
+import android.widget.Toast;\r
+\r
+import com.example.ti.ble.common.BluetoothLeService;\r
+import com.example.ti.ble.common.GattInfo;\r
+import com.example.ti.ble.common.HelpView;\r
+import com.example.ti.ble.sensortag.R;\r
+import com.example.ti.util.Point3D;\r
+\r
+public class DeviceActivity extends ViewPagerActivity {\r
+       // Log\r
+       // private static String TAG = "DeviceActivity";\r
+\r
+       // Activity\r
+       public static final String EXTRA_DEVICE = "EXTRA_DEVICE";\r
+       private static final int PREF_ACT_REQ = 0;\r
+       private static final int FWUPDATE_ACT_REQ = 1;\r
+\r
+       private DeviceView mDeviceView = null;\r
+\r
+       // BLE\r
+       private BluetoothLeService mBtLeService = null;\r
+       private BluetoothDevice mBluetoothDevice = null;\r
+       private BluetoothGatt mBtGatt = null;\r
+       private List<BluetoothGattService> mServiceList = null;\r
+       private static final int GATT_TIMEOUT = 250; // milliseconds\r
+       private boolean mServicesRdy = false;\r
+       private boolean mIsReceiving = false;\r
+\r
+       // SensorTagGatt\r
+       private List<Sensor> mEnabledSensors = new ArrayList<Sensor>();\r
+       private BluetoothGattService mOadService = null;\r
+       private BluetoothGattService mConnControlService = null;\r
+       private boolean mMagCalibrateRequest = true;\r
+       private boolean mHeightCalibrateRequest = true;\r
+       private boolean mIsSensorTag2;\r
+       private String mFwRev;\r
+\r
+       public DeviceActivity() {\r
+               mResourceFragmentPager = R.layout.fragment_pager;\r
+               mResourceIdPager = R.id.pager;\r
+               mFwRev = new String("1.5"); // Assuming all SensorTags are up to date until actual FW revision is read\r
+       }\r
+\r
+       public static DeviceActivity getInstance() {\r
+               return (DeviceActivity) mThis;\r
+       }\r
+\r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);\r
+               super.onCreate(savedInstanceState);\r
+               Intent intent = getIntent();\r
+\r
+               // BLE\r
+               mBtLeService = BluetoothLeService.getInstance();\r
+               mBluetoothDevice = intent.getParcelableExtra(EXTRA_DEVICE);\r
+               mServiceList = new ArrayList<BluetoothGattService>();\r
+\r
+               // Determine type of SensorTagGatt\r
+               String deviceName = mBluetoothDevice.getName();\r
+               mIsSensorTag2 = deviceName.equals("SensorTag2");\r
+               if (mIsSensorTag2)\r
+                       PreferenceManager.setDefaultValues(this, R.xml.preferences2, false);\r
+               else\r
+                       PreferenceManager.setDefaultValues(this, R.xml.preferences, false);\r
+               // Log.i(TAG, "Preferences for: " + deviceName);\r
+\r
+               // GUI\r
+               mDeviceView = new DeviceView();\r
+               mSectionsPagerAdapter.addSection(mDeviceView, "Sensors");\r
+               HelpView hw = new HelpView();\r
+               hw.setParameters("help_device.html", R.layout.fragment_help, R.id.webpage);\r
+               mSectionsPagerAdapter.addSection(hw, "Help");\r
+\r
+               // GATT database\r
+               Resources res = getResources();\r
+               XmlResourceParser xpp = res.getXml(R.xml.gatt_uuid);\r
+               new GattInfo(xpp);\r
+\r
+               // Initialize sensor list\r
+               updateSensorList();\r
+       }\r
+\r
+       @Override\r
+       public void onDestroy() {\r
+               super.onDestroy();\r
+               finishActivity(PREF_ACT_REQ);\r
+               finishActivity(FWUPDATE_ACT_REQ);\r
+       }\r
+\r
+       @Override\r
+       public boolean onCreateOptionsMenu(Menu menu) {\r
+               this.optionsMenu = menu;\r
+               // Inflate the menu items for use in the action bar\r
+               MenuInflater inflater = getMenuInflater();\r
+               inflater.inflate(R.menu.device_activity_actions, menu);\r
+               return super.onCreateOptionsMenu(menu);\r
+       }\r
+\r
+       @Override\r
+       public boolean onOptionsItemSelected(MenuItem item) {\r
+               // Handle presses on the action bar items\r
+               switch (item.getItemId()) {\r
+               case R.id.opt_prefs:\r
+                       startPreferenceActivity();\r
+                       break;\r
+               case R.id.opt_fwupdate:\r
+                       startOadActivity();\r
+                       break;\r
+               case R.id.opt_about:\r
+                       openAboutDialog();\r
+                       break;\r
+               default:\r
+                       return super.onOptionsItemSelected(item);\r
+               }\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       protected void onResume() {\r
+               // Log.d(TAG, "onResume");\r
+               super.onResume();\r
+               if (!mIsReceiving) {\r
+                       registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());\r
+                       mIsReceiving = true;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected void onPause() {\r
+               // Log.d(TAG, "onPause");\r
+               super.onPause();\r
+               if (mIsReceiving) {\r
+                       unregisterReceiver(mGattUpdateReceiver);\r
+                       mIsReceiving = false;\r
+               }\r
+       }\r
+\r
+       private static IntentFilter makeGattUpdateIntentFilter() {\r
+               final IntentFilter fi = new IntentFilter();\r
+               fi.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);\r
+               fi.addAction(BluetoothLeService.ACTION_DATA_NOTIFY);\r
+               fi.addAction(BluetoothLeService.ACTION_DATA_WRITE);\r
+               fi.addAction(BluetoothLeService.ACTION_DATA_READ);\r
+               return fi;\r
+       }\r
+\r
+       void onViewInflated(View view) {\r
+               // Log.d(TAG, "Gatt view ready");\r
+               setBusy(true);\r
+\r
+               // Set title bar to device name\r
+               setTitle(mBluetoothDevice.getName());\r
+\r
+               // Create GATT object\r
+               mBtGatt = BluetoothLeService.getBtGatt();\r
+\r
+               // Start service discovery\r
+               if (!mServicesRdy && mBtGatt != null) {\r
+                       if (mBtLeService.getNumServices() == 0)\r
+                               discoverServices();\r
+                       else {\r
+                               displayServices();\r
+                               enableDataCollection(true);\r
+                       }\r
+               }\r
+       }\r
+\r
+       //\r
+       // Application implementation\r
+       //\r
+       private void updateSensorList() {\r
+               mEnabledSensors.clear();\r
+\r
+               for (int i = 0; i < Sensor.SENSOR_LIST.length; i++) {\r
+                       Sensor sensor = Sensor.SENSOR_LIST[i];\r
+                       if (isEnabledByPrefs(sensor)) {\r
+                               mEnabledSensors.add(sensor);\r
+                       }\r
+               }\r
+       }\r
+\r
+       boolean isSensorTag2() {\r
+               return mIsSensorTag2;\r
+       }\r
+\r
+       String firmwareRevision() {\r
+               return mFwRev;\r
+       }\r
+\r
+       boolean isEnabledByPrefs(final Sensor sensor) {\r
+               String preferenceKeyString = "pref_"\r
+                   + sensor.name().toLowerCase(Locale.ENGLISH) + "_on";\r
+\r
+               SharedPreferences prefs = PreferenceManager\r
+                   .getDefaultSharedPreferences(this);\r
+\r
+               Boolean defaultValue = true;\r
+               return prefs.getBoolean(preferenceKeyString, defaultValue);\r
+       }\r
+\r
+       BluetoothGattService getOadService() {\r
+               return mOadService;\r
+       }\r
+\r
+       BluetoothGattService getConnControlService() {\r
+               return mConnControlService;\r
+       }\r
+\r
+       private void startOadActivity() {\r
+    // For the moment OAD does not work on Galaxy S3 (disconnects on parameter update)\r
+    if (Build.MODEL.contains("I9300")) {\r
+                       Toast.makeText(this, "OAD not available on this Android device",\r
+                           Toast.LENGTH_LONG).show();\r
+                       return;\r
+    }\r
+       \r
+               if (mOadService != null && mConnControlService != null) {\r
+                       // Disable sensors and notifications when the OAD dialog is open\r
+                       enableDataCollection(false);\r
+                       // Launch OAD\r
+                       final Intent i = new Intent(this, FwUpdateActivity.class);\r
+                       startActivityForResult(i, FWUPDATE_ACT_REQ);\r
+               } else {\r
+                       Toast.makeText(this, "OAD not available on this BLE device",\r
+                           Toast.LENGTH_LONG).show();\r
+               }\r
+       }\r
+\r
+       private void startPreferenceActivity() {\r
+               // Disable sensors and notifications when the settings dialog is open\r
+               enableDataCollection(false);\r
+               // Launch preferences\r
+               final Intent i = new Intent(this, PreferencesActivity.class);\r
+               i.putExtra(PreferencesActivity.EXTRA_SHOW_FRAGMENT,\r
+                   PreferencesFragment.class.getName());\r
+               i.putExtra(PreferencesActivity.EXTRA_NO_HEADERS, true);\r
+               i.putExtra(EXTRA_DEVICE, mBluetoothDevice);\r
+               startActivityForResult(i, PREF_ACT_REQ);\r
+       }\r
+\r
+       private void checkOad() {\r
+               // Check if OAD is supported (needs OAD and Connection Control service)\r
+               mOadService = null;\r
+               mConnControlService = null;\r
+\r
+               for (int i = 0; i < mServiceList.size()\r
+                   && (mOadService == null || mConnControlService == null); i++) {\r
+                       BluetoothGattService srv = mServiceList.get(i);\r
+                       if (srv.getUuid().equals(GattInfo.OAD_SERVICE_UUID)) {\r
+                               mOadService = srv;\r
+                       }\r
+                       if (srv.getUuid().equals(GattInfo.CC_SERVICE_UUID)) {\r
+                               mConnControlService = srv;\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void discoverServices() {\r
+               if (mBtGatt.discoverServices()) {\r
+                       mServiceList.clear();\r
+                       setBusy(true);\r
+                       setStatus("Service discovery started");\r
+               } else {\r
+                       setError("Service discovery start failed");\r
+               }\r
+       }\r
+\r
+       private void setBusy(boolean b) {\r
+               mDeviceView.setBusy(b);\r
+       }\r
+\r
+       private void displayServices() {\r
+               mServicesRdy = true;\r
+\r
+               try {\r
+                       mServiceList = mBtLeService.getSupportedGattServices();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+                       mServicesRdy = false;\r
+               }\r
+\r
+               // Characteristics descriptor readout done\r
+               if (!mServicesRdy) {\r
+                       setError("Failed to read services");\r
+               }\r
+       }\r
+\r
+       private void setError(String txt) {\r
+               setBusy(false);\r
+               Toast.makeText(this, txt, Toast.LENGTH_LONG).show();\r
+       }\r
+\r
+       private void setStatus(String txt) {\r
+               Toast.makeText(this, txt, Toast.LENGTH_SHORT).show();\r
+       }\r
+\r
+       private void enableSensors(boolean f) {\r
+               final boolean enable = f;\r
+\r
+               for (Sensor sensor : mEnabledSensors) {\r
+                       UUID servUuid = sensor.getService();\r
+                       UUID confUuid = sensor.getConfig();\r
+\r
+                       // Skip keys\r
+                       if (confUuid == null)\r
+                               break;\r
+\r
+                       if (!mIsSensorTag2) {\r
+                               // Barometer calibration\r
+                               if (confUuid.equals(SensorTagGatt.UUID_BAR_CONF) && enable) {\r
+                                       calibrateBarometer();\r
+                               }\r
+                       }\r
+\r
+                       BluetoothGattService serv = mBtGatt.getService(servUuid);\r
+                       if (serv != null) {\r
+                               BluetoothGattCharacteristic charac = serv.getCharacteristic(confUuid);\r
+                               byte value = enable ? sensor.getEnableSensorCode()\r
+                                   : Sensor.DISABLE_SENSOR_CODE;\r
+                               if (mBtLeService.writeCharacteristic(charac, value)) {\r
+                                       mBtLeService.waitIdle(GATT_TIMEOUT);\r
+                               } else {\r
+                                       setError("Sensor config failed: " + serv.getUuid().toString());\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void enableNotifications(boolean f) {\r
+               final boolean enable = f;\r
+\r
+               for (Sensor sensor : mEnabledSensors) {\r
+                       UUID servUuid = sensor.getService();\r
+                       UUID dataUuid = sensor.getData();\r
+                       BluetoothGattService serv = mBtGatt.getService(servUuid);\r
+                       if (serv != null) {\r
+                               BluetoothGattCharacteristic charac = serv.getCharacteristic(dataUuid);\r
+\r
+                               if (mBtLeService.setCharacteristicNotification(charac, enable)) {\r
+                                       mBtLeService.waitIdle(GATT_TIMEOUT);\r
+                                       try {\r
+                                               Thread.sleep(50);\r
+                                       } catch (InterruptedException e) {\r
+                                               e.printStackTrace();\r
+                                       }\r
+                               } else {\r
+                                       setError("Sensor notification failed: " + serv.getUuid().toString());\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void enableDataCollection(boolean enable) {\r
+               setBusy(true);\r
+               enableSensors(enable);\r
+               enableNotifications(enable);\r
+               setBusy(false);\r
+       }\r
+\r
+       /*\r
+        * Calibrating the barometer includes\r
+        * \r
+        * 1. Write calibration code to configuration characteristic. 2. Read\r
+        * calibration values from sensor, either with notifications or a normal read.\r
+        * 3. Use calibration values in formulas when interpreting sensor values.\r
+        */\r
+       private void calibrateBarometer() {\r
+               if (mIsSensorTag2)\r
+                       return;\r
+\r
+               UUID servUuid = Sensor.BAROMETER.getService();\r
+               UUID configUuid = Sensor.BAROMETER.getConfig();\r
+               BluetoothGattService serv = mBtGatt.getService(servUuid);\r
+               BluetoothGattCharacteristic config = serv.getCharacteristic(configUuid);\r
+\r
+               // Write the calibration code to the configuration registers\r
+               mBtLeService.writeCharacteristic(config, Sensor.CALIBRATE_SENSOR_CODE);\r
+               mBtLeService.waitIdle(GATT_TIMEOUT);\r
+               BluetoothGattCharacteristic calibrationCharacteristic = serv\r
+                   .getCharacteristic(SensorTagGatt.UUID_BAR_CALI);\r
+               mBtLeService.readCharacteristic(calibrationCharacteristic);\r
+               mBtLeService.waitIdle(GATT_TIMEOUT);\r
+       }\r
+\r
+       private void getFirmwareRevison() {\r
+               UUID servUuid = SensorTagGatt.UUID_DEVINFO_SERV;\r
+               UUID charUuid = SensorTagGatt.UUID_DEVINFO_FWREV;\r
+               BluetoothGattService serv = mBtGatt.getService(servUuid);\r
+               BluetoothGattCharacteristic charFwrev = serv.getCharacteristic(charUuid);\r
+\r
+               // Write the calibration code to the configuration registers\r
+               mBtLeService.readCharacteristic(charFwrev);\r
+               mBtLeService.waitIdle(GATT_TIMEOUT);\r
+\r
+       }\r
+\r
+       void calibrateMagnetometer() {\r
+               MagnetometerCalibrationCoefficients.INSTANCE.val.x = 0.0;\r
+               MagnetometerCalibrationCoefficients.INSTANCE.val.y = 0.0;\r
+               MagnetometerCalibrationCoefficients.INSTANCE.val.z = 0.0;\r
+\r
+               mMagCalibrateRequest = true;\r
+       }\r
+\r
+       void calibrateHeight() {\r
+               mHeightCalibrateRequest = true;\r
+       }\r
+\r
+       // Activity result handling\r
+       protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
+               super.onActivityResult(requestCode, resultCode, data);\r
+\r
+               switch (requestCode) {\r
+               case PREF_ACT_REQ:\r
+                       mDeviceView.updateVisibility();\r
+                       Toast.makeText(this, "Applying preferences", Toast.LENGTH_SHORT).show();\r
+                       if (!mIsReceiving) {\r
+                               mIsReceiving = true;\r
+                               registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());\r
+                       }\r
+\r
+                       updateSensorList();\r
+                       enableDataCollection(true);\r
+                       break;\r
+               case FWUPDATE_ACT_REQ:\r
+                       // FW update cancelled so resume\r
+                       enableDataCollection(true);\r
+                       break;\r
+               default:\r
+                       setError("Unknown request code");\r
+                       break;\r
+               }\r
+       }\r
+\r
+       private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {\r
+               @Override\r
+               public void onReceive(Context context, Intent intent) {\r
+                       final String action = intent.getAction();\r
+                       int status = intent.getIntExtra(BluetoothLeService.EXTRA_STATUS,\r
+                           BluetoothGatt.GATT_SUCCESS);\r
+\r
+                       if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {\r
+                               if (status == BluetoothGatt.GATT_SUCCESS) {\r
+                                       setStatus("Service discovery complete");\r
+                                       displayServices();\r
+                                       checkOad();\r
+                                       enableDataCollection(true);\r
+                                       getFirmwareRevison();\r
+                               } else {\r
+                                       Toast.makeText(getApplication(), "Service discovery failed",\r
+                                           Toast.LENGTH_LONG).show();\r
+                                       return;\r
+                               }\r
+                       } else if (BluetoothLeService.ACTION_DATA_NOTIFY.equals(action)) {\r
+                               // Notification\r
+                               byte[] value = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);\r
+                               String uuidStr = intent.getStringExtra(BluetoothLeService.EXTRA_UUID);\r
+                               onCharacteristicChanged(uuidStr, value);\r
+                       } else if (BluetoothLeService.ACTION_DATA_WRITE.equals(action)) {\r
+                               // Data written\r
+                               String uuidStr = intent.getStringExtra(BluetoothLeService.EXTRA_UUID);\r
+                               onCharacteristicWrite(uuidStr, status);\r
+                       } else if (BluetoothLeService.ACTION_DATA_READ.equals(action)) {\r
+                               // Data read\r
+                               String uuidStr = intent.getStringExtra(BluetoothLeService.EXTRA_UUID);\r
+                               byte[] value = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);\r
+                               onCharacteristicsRead(uuidStr, value, status);\r
+                       }\r
+\r
+                       if (status != BluetoothGatt.GATT_SUCCESS) {\r
+                               setError("GATT error code: " + status);\r
+                       }\r
+               }\r
+       };\r
+\r
+       private void onCharacteristicWrite(String uuidStr, int status) {\r
+               // Log.d(TAG, "onCharacteristicWrite: " + uuidStr);\r
+       }\r
+\r
+       private void onCharacteristicChanged(String uuidStr, byte[] value) {\r
+               if (mDeviceView != null) {\r
+                       if (mMagCalibrateRequest) {\r
+                               if (uuidStr.equals(SensorTagGatt.UUID_MAG_DATA.toString())) {\r
+                                       Point3D v = Sensor.MAGNETOMETER.convert(value);\r
+\r
+                                       MagnetometerCalibrationCoefficients.INSTANCE.val = v;\r
+                                       mMagCalibrateRequest = false;\r
+                                       Toast.makeText(this, "Magnetometer calibrated", Toast.LENGTH_SHORT)\r
+                                           .show();\r
+                               }\r
+                       }\r
+\r
+                       if (mHeightCalibrateRequest) {\r
+                               if (uuidStr.equals(SensorTagGatt.UUID_BAR_DATA.toString())) {\r
+                                       Point3D v = Sensor.BAROMETER.convert(value);\r
+\r
+                                       BarometerCalibrationCoefficients.INSTANCE.heightCalibration = v.x;\r
+                                       mHeightCalibrateRequest = false;\r
+                                       Toast.makeText(this, "Height measurement calibrated",\r
+                                           Toast.LENGTH_SHORT).show();\r
+                               }\r
+                       }\r
+\r
+                       mDeviceView.onCharacteristicChanged(uuidStr, value);\r
+               }\r
+       }\r
+\r
+       private void onCharacteristicsRead(String uuidStr, byte[] value, int status) {\r
+               // Log.i(TAG, "onCharacteristicsRead: " + uuidStr);\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_DEVINFO_FWREV.toString())) {\r
+                       mFwRev = new String(value, 0, 3);\r
+                       Toast.makeText(this, "Firmware revision: " + mFwRev,Toast.LENGTH_LONG).show();\r
+               }\r
+\r
+               if (mIsSensorTag2)\r
+                       return;\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_BAR_CALI.toString())) {\r
+                       // Sanity check\r
+                       if (value.length != 16)\r
+                               return;\r
+                       \r
+                       // Barometer calibration values are read.\r
+                       List<Integer> cal = new ArrayList<Integer>();\r
+                       for (int offset = 0; offset < 8; offset += 2) {\r
+                               Integer lowerByte = (int) value[offset] & 0xFF;\r
+                               Integer upperByte = (int) value[offset + 1] & 0xFF;\r
+                               cal.add((upperByte << 8) + lowerByte);\r
+                       }\r
+\r
+                       for (int offset = 8; offset < 16; offset += 2) {\r
+                               Integer lowerByte = (int) value[offset] & 0xFF;\r
+                               Integer upperByte = (int) value[offset + 1];\r
+                               cal.add((upperByte << 8) + lowerByte);\r
+                       }\r
+\r
+                       BarometerCalibrationCoefficients.INSTANCE.barometerCalibrationCoefficients = cal;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/DeviceView.java b/src/com/example/ti/ble/sensortag/DeviceView.java
new file mode 100644 (file)
index 0000000..8178937
--- /dev/null
@@ -0,0 +1,309 @@
+/**************************************************************************************************\r
+  Filename:       DeviceView.java\r
+  Revised:        $Date: 2013-08-30 12:02:37 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27470 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import java.text.DecimalFormat;\r
+\r
+import android.os.Bundle;\r
+import android.support.v4.app.Fragment;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.View.OnClickListener;\r
+import android.view.ViewGroup;\r
+import android.widget.ImageView;\r
+import android.widget.TableLayout;\r
+import android.widget.TableRow;\r
+import android.widget.TextView;\r
+\r
+import com.example.ti.util.Point3D;\r
+\r
+// Fragment for Device View\r
+public class DeviceView extends Fragment {\r
+\r
+       // Sensor table; the iD corresponds to row number\r
+       private static final int ID_OFFSET = 0;\r
+       private static final int ID_KEY = 0;\r
+       private static final int ID_ACC = 1;\r
+       private static final int ID_MAG = 2;\r
+       private static final int ID_OPT = 2;\r
+       private static final int ID_GYR = 3;\r
+       private static final int ID_OBJ = 4;\r
+       private static final int ID_AMB = 5;\r
+       private static final int ID_HUM = 6;\r
+       private static final int ID_BAR = 7;\r
+\r
+       public static DeviceView mInstance = null;\r
+\r
+       // GUI\r
+       private TableLayout table;\r
+       private TextView mAccValue;\r
+       private TextView mMagValue;\r
+       private TextView mLuxValue;\r
+       private TextView mGyrValue;\r
+       private TextView mObjValue;\r
+       private TextView mAmbValue;\r
+       private TextView mHumValue;\r
+       private TextView mBarValue;\r
+       private ImageView mButton;\r
+       private ImageView mRelay;\r
+       private TableRow mMagPanel;\r
+       private TableRow mBarPanel;\r
+\r
+       // House-keeping\r
+       private DecimalFormat decimal = new DecimalFormat("+0.00;-0.00");\r
+       private DeviceActivity mActivity;\r
+       private static final double PA_PER_METER = 12.0;\r
+       private boolean mIsSensorTag2;\r
+       private boolean mBusy;\r
+\r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+           Bundle savedInstanceState) {\r
+               mInstance = this;\r
+               mActivity = (DeviceActivity) getActivity();\r
+               mIsSensorTag2 = mActivity.isSensorTag2();\r
+\r
+               // The last two arguments ensure LayoutParams are inflated properly.\r
+               View view;\r
+\r
+               if (mIsSensorTag2) {\r
+                       view = inflater.inflate(R.layout.services_browser2, container, false);\r
+                       table = (TableLayout) view.findViewById(R.id.services_browser_layout2);\r
+                       mLuxValue = (TextView) view.findViewById(R.id.luxometerTxt);\r
+                       mMagPanel = null;\r
+                       mRelay = (ImageView) view.findViewById(R.id.relay);\r
+               } else {\r
+                       view = inflater.inflate(R.layout.services_browser, container, false);\r
+                       table = (TableLayout) view.findViewById(R.id.services_browser_layout);\r
+                       mMagValue = (TextView) view.findViewById(R.id.magnetometerTxt);\r
+                       mMagPanel = (TableRow) view.findViewById(R.id.magPanel);\r
+                       mRelay = null;\r
+               }\r
+\r
+               // UI widgets\r
+               mAccValue = (TextView) view.findViewById(R.id.accelerometerTxt);\r
+               mGyrValue = (TextView) view.findViewById(R.id.gyroscopeTxt);\r
+               mObjValue = (TextView) view.findViewById(R.id.objTemperatureText);\r
+               mAmbValue = (TextView) view.findViewById(R.id.ambientTemperatureTxt);\r
+               mHumValue = (TextView) view.findViewById(R.id.humidityTxt);\r
+               mBarValue = (TextView) view.findViewById(R.id.barometerTxt);\r
+               mButton = (ImageView) view.findViewById(R.id.buttons);\r
+\r
+               // Support for calibration\r
+               mBarPanel = (TableRow) view.findViewById(R.id.barPanel);\r
+               OnClickListener cl = new OnClickListener() {\r
+                       public void onClick(View v) {\r
+                               switch (v.getId()) {\r
+                               case R.id.magPanel:\r
+                                       mActivity.calibrateMagnetometer();\r
+                                       break;\r
+                               case R.id.barPanel:\r
+                                       mActivity.calibrateHeight();\r
+                                       break;\r
+                               default:\r
+                               }\r
+                       }\r
+               };\r
+\r
+               if (mMagPanel != null)\r
+                       mMagPanel.setOnClickListener(cl);\r
+               mBarPanel.setOnClickListener(cl);\r
+\r
+               // Notify activity that UI has been inflated\r
+               mActivity.onViewInflated(view);\r
+\r
+               return view;\r
+       }\r
+\r
+       @Override\r
+       public void onResume() {\r
+               super.onResume();\r
+               updateVisibility();\r
+       }\r
+\r
+       @Override\r
+       public void onPause() {\r
+               super.onPause();\r
+       }\r
+\r
+       /**\r
+        * Handle changes in sensor values\r
+        * */\r
+       public void onCharacteristicChanged(String uuidStr, byte[] rawValue) {\r
+               Point3D v;\r
+               String msg;\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_ACC_DATA.toString())) {\r
+                       v = Sensor.ACCELEROMETER.convert(rawValue);\r
+                       msg = decimal.format(v.x) + "\n" + decimal.format(v.y) + "\n"\r
+                           + decimal.format(v.z) + "\n";\r
+                       mAccValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_MAG_DATA.toString())) {\r
+                       v = Sensor.MAGNETOMETER.convert(rawValue);\r
+                       msg = decimal.format(v.x) + "\n" + decimal.format(v.y) + "\n"\r
+                           + decimal.format(v.z) + "\n";\r
+                       mMagValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_OPT_DATA.toString())) {\r
+                       v = Sensor.LUXOMETER.convert(rawValue);\r
+                       msg = decimal.format(v.x) + "\n";\r
+                       mLuxValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_GYR_DATA.toString())) {\r
+                       v = Sensor.GYROSCOPE.convert(rawValue);\r
+                       msg = decimal.format(v.x) + "\n" + decimal.format(v.y) + "\n"\r
+                           + decimal.format(v.z) + "\n";\r
+                       mGyrValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_IRT_DATA.toString())) {\r
+                       v = Sensor.IR_TEMPERATURE.convert(rawValue);\r
+                       msg = decimal.format(v.x) + "\n";\r
+                       mAmbValue.setText(msg);\r
+                       msg = decimal.format(v.y) + "\n";\r
+                       mObjValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_HUM_DATA.toString())) {\r
+                       v = Sensor.HUMIDITY.convert(rawValue);\r
+                       msg = decimal.format(v.x) + "\n";\r
+                       mHumValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_BAR_DATA.toString())) {\r
+                       v = Sensor.BAROMETER.convert(rawValue);\r
+                       \r
+                       double h = (v.x - BarometerCalibrationCoefficients.INSTANCE.heightCalibration)\r
+                           / PA_PER_METER;\r
+                       h = (double) Math.round(-h * 10.0) / 10.0;\r
+                       msg = decimal.format(v.x / 100.0f) + "\n" + h;\r
+                       mBarValue.setText(msg);\r
+               }\r
+\r
+               if (uuidStr.equals(SensorTagGatt.UUID_KEY_DATA.toString())) {\r
+                       int keys = rawValue[0];\r
+                       SimpleKeysStatus s;\r
+                       final int imgBtn;\r
+                       s = Sensor.SIMPLE_KEYS.convertKeys((byte) (keys&3));\r
+\r
+                       switch (s) {\r
+                       case OFF_ON:\r
+                               imgBtn = R.drawable.buttonsoffon;\r
+                               setBusy(true);\r
+                               break;\r
+                       case ON_OFF:\r
+                               imgBtn = R.drawable.buttonsonoff;\r
+                               setBusy(true);\r
+                               break;\r
+                       case ON_ON:\r
+                               imgBtn = R.drawable.buttonsonon;\r
+                               break;\r
+                       default:\r
+                               imgBtn = R.drawable.buttonsoffoff;\r
+                               setBusy(false);\r
+                               break;\r
+                       }\r
+\r
+                       mButton.setImageResource(imgBtn);\r
+\r
+                       if (mIsSensorTag2) {\r
+                               // Only applicable for SensorTag2\r
+                               final int imgRelay;\r
+\r
+                               if ((keys&4) == 4) {\r
+                                       imgRelay = R.drawable.reed_open;\r
+                               } else {\r
+                                       imgRelay = R.drawable.reed_closed;\r
+                               }\r
+                               mRelay.setImageResource(imgRelay);\r
+                       }\r
+               }\r
+       }\r
+\r
+       void updateVisibility() {\r
+               showItem(ID_KEY, mActivity.isEnabledByPrefs(Sensor.SIMPLE_KEYS));\r
+               showItem(ID_ACC, mActivity.isEnabledByPrefs(Sensor.ACCELEROMETER));\r
+               if (mIsSensorTag2)\r
+                       showItem(ID_OPT, mActivity.isEnabledByPrefs(Sensor.LUXOMETER));\r
+               else\r
+                       showItem(ID_MAG, mActivity.isEnabledByPrefs(Sensor.MAGNETOMETER));\r
+               showItem(ID_GYR, mActivity.isEnabledByPrefs(Sensor.GYROSCOPE));\r
+               showItem(ID_OBJ, mActivity.isEnabledByPrefs(Sensor.IR_TEMPERATURE));\r
+               showItem(ID_AMB, mActivity.isEnabledByPrefs(Sensor.IR_TEMPERATURE));\r
+               showItem(ID_HUM, mActivity.isEnabledByPrefs(Sensor.HUMIDITY));\r
+               showItem(ID_BAR, mActivity.isEnabledByPrefs(Sensor.BAROMETER));\r
+       }\r
+\r
+       private void showItem(int id, boolean visible) {\r
+               View hdr = table.getChildAt(id * 2 + ID_OFFSET);\r
+               View txt = table.getChildAt(id * 2 + ID_OFFSET + 1);\r
+               int vc = visible ? View.VISIBLE : View.GONE;\r
+               hdr.setVisibility(vc);\r
+               txt.setVisibility(vc);\r
+       }\r
+\r
+\r
+       void setBusy(boolean f) {\r
+               if (f != mBusy)\r
+               {\r
+                       mActivity.showBusyIndicator(f);\r
+                       mBusy = f;\r
+               }\r
+       }\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/FileActivity.java b/src/com/example/ti/ble/sensortag/FileActivity.java
new file mode 100644 (file)
index 0000000..55c49b1
--- /dev/null
@@ -0,0 +1,251 @@
+/**************************************************************************************************\r
+  Filename:       FileActivity.java\r
+  Revised:        $Date: 2013-08-30 12:02:37 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27470 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import java.io.File;\r
+import java.io.FilenameFilter;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import android.app.Activity;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.os.Bundle;\r
+import android.os.Environment;\r
+import android.util.Log;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.AdapterView;\r
+import android.widget.AdapterView.OnItemClickListener;\r
+import android.widget.BaseAdapter;\r
+import android.widget.Button;\r
+import android.widget.ListView;\r
+import android.widget.TextView;\r
+import android.widget.Toast;\r
+\r
+import com.example.ti.ble.sensortag.R;\r
+\r
+public class FileActivity extends Activity {\r
+  public final static String EXTRA_FILENAME = "ti.android.ble.devicemonitor.FILENAME";\r
+\r
+       private static final String TAG = "FileActivity";\r
+  \r
+  // GUI\r
+  private FileAdapter mFileAdapter;\r
+  private ListView mLwFileList;\r
+  private TextView mTwDirName;\r
+  private Button mConfirm;\r
+\r
+  // Housekeeping\r
+  private String mSelectedFile;\r
+  private List<String> mFileList;\r
+  private String mDirectoryName;\r
+  private File mDir;\r
+\r
+  public FileActivity() {\r
+    Log.i(TAG, "construct");\r
+  }\r
+\r
+  @Override\r
+  public void onCreate(Bundle savedInstanceState) {\r
+    super.onCreate(savedInstanceState);\r
+    setContentView(R.layout.activity_file);\r
+\r
+    Intent i = getIntent();\r
+    mDirectoryName = i.getStringExtra(FwUpdateActivity.EXTRA_MESSAGE);\r
+    mDir = Environment.getExternalStoragePublicDirectory(mDirectoryName);\r
+    Log.i(TAG, mDirectoryName);\r
+\r
+    mTwDirName = (TextView) findViewById(R.id.tw_directory);\r
+    mConfirm = (Button) findViewById(R.id.btn_confirm);\r
+    mLwFileList = (ListView) findViewById(R.id.lw_file);\r
+    mLwFileList.setOnItemClickListener(mFileClickListener);\r
+\r
+    // Characteristics list\r
+    mFileList = new ArrayList<String>();\r
+    mFileAdapter = new FileAdapter(this, mFileList);\r
+    mLwFileList.setAdapter(mFileAdapter);\r
+\r
+    if (mDir.exists()) {\r
+       mTwDirName.setText(mDir.getAbsolutePath());\r
+      FilenameFilter textFilter = new FilenameFilter() {\r
+               public boolean accept(File dir, String name) {\r
+                       String lowercaseName = name.toLowerCase();\r
+                       if (lowercaseName.endsWith(".bin")) {\r
+                               return true;\r
+                       } else {\r
+                               return false;\r
+                       }\r
+               }\r
+       };\r
+\r
+      Log.i(TAG, mDir.getPath());\r
+      \r
+       File[] files = mDir.listFiles(textFilter);\r
+               for (File file : files) {\r
+                       if (!file.isDirectory()) {\r
+                               mFileList.add(file.getName());\r
+                       }\r
+               }\r
+      \r
+               if (mFileList.size() == 0)\r
+        Toast.makeText(this, "No OAD images available", Toast.LENGTH_LONG).show();             \r
+    } else {\r
+      Toast.makeText(this, mDirectoryName + " does not exist", Toast.LENGTH_LONG).show();\r
+    }\r
+    \r
+    if (mFileList.size() > 0)\r
+       mFileAdapter.setSelectedPosition(0);\r
+    else\r
+       mConfirm.setText("Cancel");\r
+  }\r
+       \r
+       \r
+  @Override\r
+  public void onDestroy() {\r
+    mFileList = null;\r
+    mFileAdapter = null;\r
+    super.onDestroy();\r
+  }\r
+\r
+  // Listener for characteristic click\r
+  private OnItemClickListener mFileClickListener = new OnItemClickListener() {\r
+    public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {\r
+\r
+      // A characteristic item has been selected\r
+      mFileAdapter.setSelectedPosition(pos);\r
+    }\r
+  };\r
+\r
+  // Callback for confirm button\r
+  public void onConfirm(View v) {\r
+    Intent i = new Intent();\r
+\r
+    if (mFileList.size() > 0) {\r
+       i.putExtra(EXTRA_FILENAME, mDir.getAbsolutePath() + File.separator + mSelectedFile);\r
+       setResult(RESULT_OK, i);\r
+    } else {\r
+       setResult(RESULT_CANCELED, i);          \r
+    }\r
+    finish();\r
+  }\r
+\r
+  //\r
+  // CLASS ServiceAdapter: handle characteristics list\r
+  //\r
+  class FileAdapter extends BaseAdapter {\r
+    Context mContext;\r
+    List<String> mFiles;\r
+    LayoutInflater mInflater;\r
+    int mSelectedPos;\r
+\r
+    public FileAdapter(Context context, List<String> files) {\r
+      mInflater = LayoutInflater.from(context);\r
+      mContext = context;\r
+      mFiles = files;\r
+      mSelectedPos = 0;\r
+    }\r
+\r
+    public int getCount() {\r
+      return mFiles.size();\r
+    }\r
+\r
+    public Object getItem(int pos) {\r
+      return mFiles.get(pos);\r
+    }\r
+\r
+    public long getItemId(int pos) {\r
+      return pos;\r
+    }\r
+\r
+    public void setSelectedPosition(int pos) {\r
+      mSelectedFile = mFileList.get(pos);\r
+      mSelectedPos = pos;\r
+      notifyDataSetChanged();\r
+    }\r
+\r
+    public int getSelectedPosition() {\r
+      return mSelectedPos;\r
+    }\r
+\r
+    public View getView(int pos, View view, ViewGroup parent) {\r
+      ViewGroup vg;\r
+\r
+      if (view != null) {\r
+        vg = (ViewGroup) view;\r
+      } else {\r
+        vg = (ViewGroup) mInflater.inflate(R.layout.element_file, null);\r
+      }\r
+\r
+      // Grab characteristic object\r
+      String file = mFiles.get(pos);\r
+\r
+      // Show name, UUID and properties\r
+      TextView twName = (TextView) vg.findViewById(R.id.name);\r
+      twName.setText(file);\r
+\r
+      // Highlight selected object\r
+      if (pos == mSelectedPos) {\r
+        twName.setTextAppearance(mContext, R.style.nameStyleSelected);\r
+      } else {\r
+        twName.setTextAppearance(mContext, R.style.nameStyle);\r
+      }\r
+\r
+      return vg;\r
+    }\r
+  }\r
+\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/FwUpdateActivity.java b/src/com/example/ti/ble/sensortag/FwUpdateActivity.java
new file mode 100644 (file)
index 0000000..15f3c2d
--- /dev/null
@@ -0,0 +1,614 @@
+/**************************************************************************************************\r
+  Filename:       FwUpdateActivity.java\r
+  Revised:        $Date: 2013-09-05 05:55:20 +0200 (to, 05 sep 2013) $\r
+  Revision:       $Revision: 27614 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.List;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+\r
+import android.app.Activity;\r
+import android.bluetooth.BluetoothGatt;\r
+import android.bluetooth.BluetoothGattCharacteristic;\r
+import android.bluetooth.BluetoothGattService;\r
+import android.content.BroadcastReceiver;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.content.IntentFilter;\r
+import android.os.Bundle;\r
+import android.os.Environment;\r
+import android.text.Html;\r
+import android.util.Log;\r
+import android.view.MenuItem;\r
+import android.view.View;\r
+import android.widget.Button;\r
+import android.widget.ImageView;\r
+import android.widget.ProgressBar;\r
+import android.widget.TextView;\r
+import android.widget.Toast;\r
+\r
+import com.example.ti.ble.common.BluetoothLeService;\r
+import com.example.ti.ble.sensortag.R;\r
+import com.example.ti.util.Conversion;\r
+\r
+public class FwUpdateActivity extends Activity {\r
+  public final static String EXTRA_MESSAGE = "com.example.ti.ble.sensortag.MESSAGE";\r
+  // Log\r
+  private static String TAG = "FwUpdateActivity";\r
+\r
+  // Activity\r
+  private static final int FILE_ACTIVITY_REQ = 0;\r
+\r
+  // Programming parameters\r
+  private static final short OAD_CONN_INTERVAL = 12; // 15 milliseconds\r
+  private static final short OAD_SUPERVISION_TIMEOUT = 50; // 500 milliseconds\r
+  private static final int GATT_WRITE_TIMEOUT = 300; // Milliseconds\r
+\r
+  private static final int FILE_BUFFER_SIZE = 0x40000;\r
+  private static final String FW_CUSTOM_DIRECTORY = Environment.DIRECTORY_DOWNLOADS;\r
+  private static final String FW_FILE_A = "SensorTagImgA.bin";\r
+  private static final String FW_FILE_B = "SensorTagImgB.bin";\r
+\r
+  private static final int OAD_BLOCK_SIZE = 16;\r
+  private static final int HAL_FLASH_WORD_SIZE = 4;\r
+  private static final int OAD_BUFFER_SIZE = 2 + OAD_BLOCK_SIZE;\r
+  private static final int OAD_IMG_HDR_SIZE = 8;\r
+       private static final long TIMER_INTERVAL = 1000;\r
+       \r
+       private static final int SEND_INTERVAL = 20; // Milliseconds (make sure this is longer than the connection interval)\r
+       private static final int BLOCKS_PER_CONNECTION = 4; // May sent up to four blocks per connection\r
+\r
+  // GUI\r
+  private TextView mTargImage;\r
+  private TextView mFileImage;\r
+  private TextView mProgressInfo;\r
+  private TextView mLog;\r
+  private ProgressBar mProgressBar;\r
+  private Button mBtnLoadA;\r
+  private Button mBtnLoadB;\r
+  private Button mBtnLoadC;\r
+  private Button mBtnStart;\r
+\r
+  // BLE\r
+  private BluetoothGattService mOadService;\r
+  private BluetoothGattService mConnControlService;\r
+  private List<BluetoothGattCharacteristic> mCharListOad;\r
+  private List<BluetoothGattCharacteristic> mCharListCc;\r
+  private BluetoothGattCharacteristic mCharIdentify = null;\r
+  private BluetoothGattCharacteristic mCharBlock = null;\r
+  private BluetoothGattCharacteristic mCharConnReq = null;\r
+  private DeviceActivity mDeviceActivity = null;\r
+  private BluetoothLeService mLeService;\r
+\r
+  // Programming\r
+  private final byte[] mFileBuffer = new byte[FILE_BUFFER_SIZE];\r
+  private final byte[] mOadBuffer = new byte[OAD_BUFFER_SIZE];\r
+  private ImgHdr mFileImgHdr = new ImgHdr();\r
+  private ImgHdr mTargImgHdr = new ImgHdr();\r
+  private Timer mTimer = null;\r
+  private ProgInfo mProgInfo = new ProgInfo();\r
+  private TimerTask mTimerTask = null;\r
+\r
+  // Housekeeping\r
+  private boolean mServiceOk = false;\r
+  private boolean mProgramming = false;\r
+  private IntentFilter mIntentFilter;\r
+\r
+\r
+  public FwUpdateActivity() {\r
+    mDeviceActivity = DeviceActivity.getInstance();\r
+\r
+    // BLE Gatt Service\r
+    mLeService = BluetoothLeService.getInstance();\r
+\r
+    // Service information\r
+    mOadService = mDeviceActivity.getOadService();\r
+    mConnControlService = mDeviceActivity.getConnControlService();\r
+\r
+    // Characteristics list\r
+    mCharListOad = mOadService.getCharacteristics();\r
+    mCharListCc = mConnControlService.getCharacteristics();\r
+\r
+    mServiceOk = mCharListOad.size() == 2 && mCharListCc.size() >= 3;\r
+    if (mServiceOk) {\r
+      mCharIdentify = mCharListOad.get(0);\r
+      mCharBlock = mCharListOad.get(1);\r
+      mCharBlock.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);\r
+      mCharConnReq = mCharListCc.get(1);\r
+    }\r
+  }\r
+\r
+  @Override\r
+  public void onCreate(Bundle savedInstanceState) {\r
+    Log.d(TAG, "onCreate");\r
+\r
+    super.onCreate(savedInstanceState);\r
+    setContentView(R.layout.activity_fwupdate);\r
+\r
+    // Icon padding\r
+    ImageView view = (ImageView) findViewById(android.R.id.home);\r
+    view.setPadding(10, 0, 20, 10);\r
+\r
+    // Context title\r
+    setTitle(R.string.title_oad);\r
+\r
+    // Initialize widgets\r
+    mProgressInfo = (TextView) findViewById(R.id.tw_info);\r
+    mTargImage = (TextView) findViewById(R.id.tw_target);\r
+    mFileImage = (TextView) findViewById(R.id.tw_file);\r
+    mLog = (TextView) findViewById(R.id.tw_log);\r
+    mProgressBar = (ProgressBar) findViewById(R.id.pb_progress);\r
+    mBtnStart = (Button) findViewById(R.id.btn_start);\r
+    mBtnStart.setEnabled(false);\r
+    mBtnLoadA = (Button) findViewById(R.id.btn_load_a);\r
+    mBtnLoadB = (Button) findViewById(R.id.btn_load_b);\r
+    mBtnLoadC = (Button) findViewById(R.id.btn_load_c);\r
+\r
+    // Sanity check\r
+    mBtnLoadA.setEnabled(mServiceOk);\r
+    mBtnLoadB.setEnabled(mServiceOk);\r
+    mBtnLoadC.setEnabled(mServiceOk);\r
+       initIntentFilter();\r
+  }\r
+\r
+  @Override\r
+  public void onDestroy() {\r
+    Log.d(TAG, "onDestroy");\r
+    super.onDestroy();\r
+    if (mTimerTask != null)\r
+      mTimerTask.cancel();\r
+    mTimer = null;\r
+  }\r
+\r
+  @Override\r
+  public void onBackPressed() {\r
+    Log.d(TAG, "onBackPressed");\r
+    if (mProgramming) {\r
+      Toast.makeText(this, R.string.prog_ogoing, Toast.LENGTH_LONG).show();\r
+    } else\r
+      super.onBackPressed();\r
+  }\r
+  \r
+  @Override\r
+  public boolean onOptionsItemSelected(MenuItem item) {\r
+    Log.d(TAG, "onOptionsItemSelected");\r
+    // Handle presses on the action bar items\r
+    switch (item.getItemId()) {\r
+    // Respond to the action bar's Up/Home button\r
+    case android.R.id.home:\r
+      onBackPressed();\r
+      return true;\r
+    default:\r
+      return super.onOptionsItemSelected(item);\r
+    }\r
+  }\r
+  \r
+  @Override \r
+  protected void onResume()\r
+  {\r
+    super.onResume();\r
+    if (mServiceOk) {\r
+       registerReceiver(mGattUpdateReceiver, mIntentFilter);\r
+       \r
+      // Read target image info\r
+      getTargetImageInfo();\r
+      \r
+               // Connection interval is too low by default\r
+               setConnectionParameters();\r
+    } else {\r
+      Toast.makeText(this, "OAD service initialisation failed", Toast.LENGTH_LONG).show();\r
+    }\r
+  }\r
+\r
+  @Override\r
+  protected void onPause() {\r
+       super.onPause();\r
+       unregisterReceiver(mGattUpdateReceiver);\r
+  }\r
+\r
+  private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {\r
+               @Override\r
+               public void onReceive(Context context, Intent intent) {\r
+\r
+                       final String action = intent.getAction();\r
+\r
+           if (BluetoothLeService.ACTION_DATA_NOTIFY.equals(action)) {\r
+                               byte [] value = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);\r
+                               String uuidStr = intent.getStringExtra(BluetoothLeService.EXTRA_UUID);\r
+                               \r
+                   if (uuidStr.equals(mCharIdentify.getUuid().toString())) {\r
+                       // Image info notification\r
+                     mTargImgHdr.ver = Conversion.buildUint16(value[1], value[0]);\r
+                     mTargImgHdr.imgType = ((mTargImgHdr.ver & 1) == 1) ? 'B' : 'A';\r
+                     mTargImgHdr.len = Conversion.buildUint16(value[3], value[2]);\r
+                     displayImageInfo(mTargImage, mTargImgHdr);\r
+                   }\r
+                   \r
+                       } else if (BluetoothLeService.ACTION_DATA_WRITE.equals(action)) {\r
+                               int status = intent.getIntExtra(BluetoothLeService.EXTRA_STATUS,BluetoothGatt.GATT_SUCCESS);\r
+                               if (status != BluetoothGatt.GATT_SUCCESS) {\r
+                                       Toast.makeText(context, "GATT error: status=" + status, Toast.LENGTH_SHORT).show();\r
+                               }\r
+                       }\r
+               }\r
+       };\r
+\r
+\r
+  private void initIntentFilter() {\r
+       mIntentFilter = new IntentFilter();\r
+       mIntentFilter.addAction(BluetoothLeService.ACTION_DATA_NOTIFY);\r
+       mIntentFilter.addAction(BluetoothLeService.ACTION_DATA_WRITE);\r
+  }\r
+\r
+  public void onStart(View v) {\r
+    if (mProgramming) {\r
+      stopProgramming();\r
+    } else {\r
+      startProgramming();\r
+    }\r
+  }\r
+\r
+  public void onLoad(View v) {\r
+    if (v.getId() == R.id.btn_load_a)\r
+      loadFile(FW_FILE_A, true);\r
+    else\r
+      loadFile(FW_FILE_B, true);\r
+    updateGui();\r
+  }\r
+\r
+  public void onLoadCustom(View v) {\r
+    Intent i = new Intent(this, FileActivity.class);\r
+    i.putExtra(EXTRA_MESSAGE, FW_CUSTOM_DIRECTORY);\r
+    startActivityForResult(i, FILE_ACTIVITY_REQ);\r
+  }\r
+\r
+  private void startProgramming() {\r
+    mLog.append("Programming started\n");\r
+    mProgramming = true;\r
+    updateGui();\r
+\r
+    // Prepare image notification\r
+    byte[] buf = new byte[OAD_IMG_HDR_SIZE + 2 + 2];\r
+    buf[0] = Conversion.loUint16(mFileImgHdr.ver);\r
+    buf[1] = Conversion.hiUint16(mFileImgHdr.ver);\r
+    buf[2] = Conversion.loUint16(mFileImgHdr.len);\r
+    buf[3] = Conversion.hiUint16(mFileImgHdr.len);\r
+    System.arraycopy(mFileImgHdr.uid, 0, buf, 4, 4);\r
+\r
+    // Send image notification\r
+    mCharIdentify.setValue(buf);\r
+    mLeService.writeCharacteristic(mCharIdentify);\r
+\r
+    // Initialize stats\r
+    mProgInfo.reset();\r
+\r
+    // Start the programming thread\r
+    new Thread(new OadTask()).start();\r
+\r
+    mTimer = new Timer();\r
+    mTimerTask = new ProgTimerTask();\r
+    mTimer.scheduleAtFixedRate(mTimerTask, 0, TIMER_INTERVAL);\r
+  }\r
+\r
+  private void stopProgramming() {\r
+    mTimer.cancel();\r
+    mTimer.purge();\r
+    mTimerTask.cancel();\r
+    mTimerTask = null;\r
+\r
+    mProgramming = false;\r
+    mProgressInfo.setText("");\r
+    mProgressBar.setProgress(0);\r
+    updateGui();\r
+\r
+    if (mProgInfo.iBlocks == mProgInfo.nBlocks) {\r
+      mLog.setText("Programming complete!\n");\r
+    } else {\r
+      mLog.append("Programming cancelled\n");\r
+    }\r
+  }\r
+\r
+  private void updateGui() {\r
+       if (mProgramming) {\r
+               // Busy: stop label, progress bar, disabled file selector\r
+               mBtnStart.setText(R.string.cancel);\r
+               mBtnLoadA.setEnabled(false);\r
+               mBtnLoadB.setEnabled(false);\r
+               mBtnLoadC.setEnabled(false);\r
+       } else {\r
+               // Idle: program label, enable file selector\r
+               mProgressBar.setProgress(0);\r
+               mBtnStart.setText(R.string.start_prog);\r
+               if (mFileImgHdr.imgType == 'A') {\r
+                       mBtnLoadA.setEnabled(false);\r
+                       mBtnLoadB.setEnabled(true);\r
+               } else if (mFileImgHdr.imgType == 'B') {\r
+                       mBtnLoadA.setEnabled(true);\r
+                       mBtnLoadB.setEnabled(false);\r
+               }\r
+               mBtnLoadC.setEnabled(true);\r
+       }\r
+  }\r
+\r
+  private boolean loadFile(String filepath, boolean isAsset) {\r
+    boolean fSuccess = false;\r
+\r
+    // Load binary file\r
+    try {\r
+      // Read the file raw into a buffer\r
+      InputStream stream;\r
+      if (isAsset) {\r
+        stream = getAssets().open(filepath);\r
+      } else {\r
+        File f = new File(filepath);\r
+        stream = new FileInputStream(f);\r
+      }\r
+      stream.read(mFileBuffer, 0, mFileBuffer.length);\r
+      stream.close();\r
+    } catch (IOException e) {\r
+      // Handle exceptions here\r
+      mLog.setText("File open failed: " + filepath + "\n");\r
+      return false;\r
+    }\r
+\r
+    // Show image info\r
+    mFileImgHdr.ver = Conversion.buildUint16(mFileBuffer[5], mFileBuffer[4]);\r
+    mFileImgHdr.len = Conversion.buildUint16(mFileBuffer[7], mFileBuffer[6]);\r
+    mFileImgHdr.imgType = ((mFileImgHdr.ver & 1) == 1) ? 'B' : 'A';\r
+    System.arraycopy(mFileBuffer, 8, mFileImgHdr.uid, 0, 4);\r
+    displayImageInfo(mFileImage, mFileImgHdr);\r
+\r
+    // Verify image types\r
+    boolean ready = mFileImgHdr.imgType != mTargImgHdr.imgType;\r
+    int resid = ready ? R.style.dataStyle1 : R.style.dataStyle2;\r
+    mFileImage.setTextAppearance(this, resid);\r
+\r
+    // Enable programming button only if image types differ\r
+    mBtnStart.setEnabled(ready);\r
+\r
+    // Expected duration\r
+    displayStats();\r
+\r
+    // Log\r
+    mLog.setText("Image " + mFileImgHdr.imgType + " selected.\n");\r
+    mLog.append(ready ? "Ready to program device!\n" : "Incompatible image, select alternative!\n");\r
+\r
+    updateGui();\r
+\r
+    return fSuccess;\r
+  }\r
+\r
+  private void displayImageInfo(TextView v, ImgHdr h) {\r
+    int imgVer = (h.ver) >> 1;\r
+    int imgSize = h.len * 4;\r
+    String s = String.format("Type: %c Ver.: %d Size: %d", h.imgType, imgVer, imgSize);\r
+    v.setText(Html.fromHtml(s));\r
+  }\r
+\r
+  private void displayStats() {\r
+    String txt;\r
+    int byteRate;\r
+    int sec = mProgInfo.iTimeElapsed / 1000;\r
+    if (sec > 0) {\r
+      byteRate = mProgInfo.iBytes / sec;\r
+    } else {\r
+      byteRate = 0;\r
+      return;\r
+    }\r
+    float timeEstimate;\r
+\r
+    timeEstimate = ((float)(mFileImgHdr.len *4) / (float)mProgInfo.iBytes) * sec;\r
+\r
+    txt = String.format("Time: %d / %d sec", sec, (int)timeEstimate);\r
+    txt += String.format("    Bytes: %d (%d/sec)", mProgInfo.iBytes, byteRate);\r
+    mProgressInfo.setText(txt);\r
+  }\r
+\r
+  private void getTargetImageInfo() {\r
+    // Enable notification\r
+    boolean ok = enableNotification(mCharIdentify, true);\r
+    // Prepare data for request (try image A and B respectively, only one of\r
+    // them will give a notification with the image info)\r
+    if (ok)\r
+      ok = writeCharacteristic(mCharIdentify, (byte) 0);\r
+    if (ok)\r
+      ok = writeCharacteristic(mCharIdentify, (byte) 1);\r
+    if (!ok)\r
+      Toast.makeText(this, "Failed to get target info", Toast.LENGTH_LONG).show();\r
+  }\r
+\r
+  private boolean writeCharacteristic(BluetoothGattCharacteristic c, byte v) {\r
+    boolean ok = mLeService.writeCharacteristic(c, v);\r
+    if (ok)\r
+      ok = mLeService.waitIdle(GATT_WRITE_TIMEOUT);\r
+    return ok;\r
+  }\r
+\r
+  private boolean enableNotification(BluetoothGattCharacteristic c, boolean enable) {\r
+    boolean ok = mLeService.setCharacteristicNotification(c, enable);\r
+    if (ok)\r
+      ok = mLeService.waitIdle(GATT_WRITE_TIMEOUT);\r
+    return ok;\r
+  }\r
+\r
+  private void setConnectionParameters() {\r
+    // Make sure connection interval is long enough for OAD (Android default connection interval is 7.5 ms)\r
+    byte[] value = { Conversion.loUint16(OAD_CONN_INTERVAL), Conversion.hiUint16(OAD_CONN_INTERVAL), Conversion.loUint16(OAD_CONN_INTERVAL),\r
+        Conversion.hiUint16(OAD_CONN_INTERVAL), 0, 0, Conversion.loUint16(OAD_SUPERVISION_TIMEOUT), Conversion.hiUint16(OAD_SUPERVISION_TIMEOUT) };\r
+    mCharConnReq.setValue(value);\r
+    mLeService.writeCharacteristic(mCharConnReq);\r
+  }\r
+\r
+\r
+  @Override\r
+  protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
+    // Check which request we're responding to\r
+    if (requestCode == FILE_ACTIVITY_REQ) {\r
+      // Make sure the request was successful\r
+      if (resultCode == RESULT_OK) {\r
+        String filename = data.getStringExtra(FileActivity.EXTRA_FILENAME);\r
+        loadFile(filename, false);\r
+      }\r
+    }\r
+  }\r
+\r
+  /*\r
+   * Called when a notification with the current image info has been received\r
+   */\r
+\r
+  private void programBlock() {\r
+       if (!mProgramming)\r
+               return;\r
+       \r
+    if (mProgInfo.iBlocks < mProgInfo.nBlocks) {\r
+      mProgramming = true;\r
+      String msg = new String();\r
+\r
+      // Prepare block\r
+      mOadBuffer[0] = Conversion.loUint16(mProgInfo.iBlocks);\r
+      mOadBuffer[1] = Conversion.hiUint16(mProgInfo.iBlocks);\r
+      System.arraycopy(mFileBuffer, mProgInfo.iBytes, mOadBuffer, 2, OAD_BLOCK_SIZE);\r
+\r
+      // Send block\r
+      mCharBlock.setValue(mOadBuffer);\r
+      boolean success = mLeService.writeCharacteristic(mCharBlock);\r
+\r
+      if (success) {\r
+        // Update stats\r
+        mProgInfo.iBlocks++;\r
+        mProgInfo.iBytes += OAD_BLOCK_SIZE;\r
+        mProgressBar.setProgress((mProgInfo.iBlocks * 100) / mProgInfo.nBlocks);\r
+        if (!mLeService.waitIdle(GATT_WRITE_TIMEOUT)) {\r
+               mProgramming = false;\r
+               success = false;\r
+               msg = "GATT write timeout\n";\r
+        }\r
+      } else {\r
+         mProgramming = false;\r
+        msg = "GATT writeCharacteristic failed\n";\r
+      }\r
+      if (!success) {\r
+       mLog.append(msg);\r
+      }\r
+    } else {\r
+      mProgramming = false;\r
+    }\r
+\r
+    if (!mProgramming) {\r
+      runOnUiThread(new Runnable() {\r
+        public void run() {\r
+          displayStats();\r
+          stopProgramming();\r
+        }\r
+      });\r
+    }\r
+  }\r
+  \r
+       private class OadTask implements Runnable {\r
+               @Override\r
+               public void run() {\r
+                       while (mProgramming) {\r
+                               try {\r
+               Thread.sleep(SEND_INTERVAL);\r
+        } catch (InterruptedException e) {\r
+               e.printStackTrace();\r
+        }\r
+                               for (int i=0; i<BLOCKS_PER_CONNECTION & mProgramming; i++) {\r
+                                       programBlock();\r
+                               }\r
+                               if ((mProgInfo.iBlocks % 100) == 0) {\r
+                                       // Display statistics each 100th block\r
+                                       runOnUiThread(new Runnable() {\r
+                                               public void run() {\r
+                                                       displayStats();\r
+                                               }\r
+                                       });\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private class ProgTimerTask extends TimerTask {\r
+    @Override\r
+    public void run() {\r
+      mProgInfo.iTimeElapsed += TIMER_INTERVAL;\r
+    }\r
+  }\r
+\r
+  private class ImgHdr {\r
+    short ver;\r
+    short len;\r
+    Character imgType;\r
+    byte[] uid = new byte[4];\r
+  }\r
+\r
+  private class ProgInfo {\r
+    int iBytes = 0; // Number of bytes programmed\r
+    short iBlocks = 0; // Number of blocks programmed\r
+    short nBlocks = 0; // Total number of blocks\r
+    int iTimeElapsed = 0; // Time elapsed in milliseconds\r
+\r
+    void reset() {\r
+      iBytes = 0;\r
+      iBlocks = 0;\r
+      iTimeElapsed = 0;\r
+      nBlocks = (short) (mFileImgHdr.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE));\r
+    }\r
+  }\r
+\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/LicenseDialog.java b/src/com/example/ti/ble/sensortag/LicenseDialog.java
new file mode 100644 (file)
index 0000000..92d88c4
--- /dev/null
@@ -0,0 +1,97 @@
+/**************************************************************************************************\r
+  Filename:       LicenseDialog.java\r
+  Revised:        $Date: 2014-01-07 16:17:34 +0100 (ti, 07 jan 2014) $\r
+  Revision:       $Revision: 28784 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import android.app.Dialog;\r
+import android.content.Context;\r
+import android.os.Bundle;\r
+import android.view.View;\r
+import android.view.Window;\r
+import android.webkit.WebView;\r
+import android.widget.Button;\r
+\r
+import com.example.ti.ble.sensortag.R;\r
+\r
+public class LicenseDialog extends Dialog {\r
+       private static LicenseDialog mDialog;\r
+       private static OkListener mOkListener;\r
+\r
+       public LicenseDialog(Context context) {\r
+               super(context);\r
+               mDialog = this;\r
+               mOkListener = new OkListener();\r
+       }\r
+\r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               requestWindowFeature(Window.FEATURE_NO_TITLE);\r
+               setContentView(R.layout.dialog_license);\r
+\r
+               // From license.html web page\r
+               WebView wv = (WebView) findViewById(R.id.webpage_license);\r
+               wv.loadUrl("file:///android_asset/license.html");\r
+\r
+               // Dismiss button\r
+               Button okButton = (Button) findViewById(R.id.buttonOK);\r
+               okButton.setOnClickListener(mOkListener);\r
+       }\r
+\r
+       private class OkListener implements android.view.View.OnClickListener {\r
+               @Override\r
+               public void onClick(View v) {\r
+                       mDialog.dismiss();\r
+               }\r
+       }\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/MagnetometerCalibrationCoefficients.java b/src/com/example/ti/ble/sensortag/MagnetometerCalibrationCoefficients.java
new file mode 100644 (file)
index 0000000..f38ed8b
--- /dev/null
@@ -0,0 +1,66 @@
+/**************************************************************************************************\r
+  Filename:       BarometerCalibrationCoefficients.java\r
+  Revised:        $Date: 2013-08-30 11:44:31 +0200 (fr, 30 aug 2013) $\r
+  Revision:       $Revision: 27454 $\r
+\r
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated\r
+\r
+  All rights reserved not granted herein.\r
+  Limited License. \r
+\r
+  Texas Instruments Incorporated grants a world-wide, royalty-free,\r
+  non-exclusive license under copyrights and patents it now or hereafter\r
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")\r
+  this software subject to the terms herein.  With respect to the foregoing patent\r
+  license, such license is granted  solely to the extent that any such patent is necessary\r
+  to Utilize the software alone.  The patent license shall not apply to any combinations which\r
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). \r
+  No hardware patent is licensed hereunder.\r
+\r
+  Redistributions must preserve existing copyright notices and reproduce this license (including the\r
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)\r
+  in the documentation and/or other materials provided with the distribution\r
+\r
+  Redistribution and use in binary form, without modification, are permitted provided that the following\r
+  conditions are met:\r
+\r
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any\r
+      software provided in binary form.\r
+    * any redistribution and use are licensed by TI for use only with TI Devices.\r
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.\r
+\r
+  If software source code is provided to you, modification and redistribution of the source code are permitted\r
+  provided that the following conditions are met:\r
+\r
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by\r
+      TI for use only with TI Devices.\r
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative\r
+      works, are licensed by TI for use only with TI Devices.\r
+\r
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or\r
+  promote products derived from this software without specific prior written permission.\r
+\r
+  DISCLAIMER.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+ **************************************************************************************************/\r
+package com.example.ti.ble.sensortag;\r
+\r
+import com.example.ti.util.Point3D;\r
+\r
+\r
+/**\r
+ * As a last-second hack i'm storing the barometer coefficients in a global.\r
+ */\r
+public enum MagnetometerCalibrationCoefficients {\r
+  INSTANCE;\r
+  Point3D val = new Point3D(0.0,0.0,0.0);\r
+}\r
diff --git a/src/com/example/ti/ble/sensortag/MainActivity.java b/src/com/example/ti/ble/sensortag/MainActivity.java
new file mode 100644 (file)
index 0000000..8395635
--- /dev/null
@@ -0,0 +1,661 @@
+/**************************************************************************************************
+  Filename:       MainActivity.java
+  Revised:        $Date: 2014-01-02 18:55:00 +0100 (to, 02 jan 2014) $
+  Revision:       $Revision: 28743 $
+
+  Copyright (c) 2013 - 2014 Texas Instruments Incorporated
+
+  All rights reserved not granted herein.
+  Limited License. 
+
+  Texas Instruments Incorporated grants a world-wide, royalty-free,
+  non-exclusive license under copyrights and patents it now or hereafter
+  owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")
+  this software subject to the terms herein.  With respect to the foregoing patent
+  license, such license is granted  solely to the extent that any such patent is necessary
+  to Utilize the software alone.  The patent license shall not apply to any combinations which
+  include this software, other than combinations with devices manufactured by or for TI (ÒTI DevicesÓ). 
+  No hardware patent is licensed hereunder.
+
+  Redistributions must preserve existing copyright notices and reproduce this license (including the
+  above copyright notice and the disclaimer and (if applicable) source code license limitations below)
+  in the documentation and/or other materials provided with the distribution
+
+  Redistribution and use in binary form, without modification, are permitted provided that the following
+  conditions are met:
+
+    * No reverse engineering, decompilation, or disassembly of this software is permitted with respect to any
+      software provided in binary form.
+    * any redistribution and use are licensed by TI for use only with TI Devices.
+    * Nothing shall obligate TI to provide you with source code for the software licensed and provided to you in object code.
+
+  If software source code is provided to you, modification and redistribution of the source code are permitted
+  provided that the following conditions are met:
+
+    * any redistribution and use of the source code, including any resulting derivative works, are licensed by
+      TI for use only with TI Devices.
+    * any redistribution and use of any object code compiled from the source code and any resulting derivative
+      works, are licensed by TI for use only with TI Devices.
+
+  Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to endorse or
+  promote products derived from this software without specific prior written permission.
+
+  DISCLAIMER.
+
+  THIS SOFTWARE IS PROVIDED BY TI AND TIÕS LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL TI AND TIÕS LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+
+ **************************************************************************************************/
+package com.example.ti.ble.sensortag;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+// import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Toast;
+
+import com.example.ti.ble.common.BleDeviceInfo;
+import com.example.ti.ble.common.BluetoothLeService;
+import com.example.ti.ble.common.HelpView;
+import com.example.ti.ble.sensortag.R;
+import com.example.ti.util.CustomToast;
+
+public class MainActivity extends ViewPagerActivity {
+       // Log
+       // private static final String TAG = "MainActivity";
+
+       // URLs
+       private static final Uri URL_FORUM = Uri
+           .parse("http://e2e.ti.com/support/low_power_rf/default.aspx?DCMP=hpa_hpa_community&HQS=NotApplicable+OT+lprf-forum");
+       private static final Uri URL_STHOME = Uri
+           .parse("http://www.ti.com/ww/en/wireless_connectivity/sensortag/index.shtml?INTC=SensorTagGatt&HQS=sensortag");
+
+       // Requests to other activities
+       private static final int REQ_ENABLE_BT = 0;
+       private static final int REQ_DEVICE_ACT = 1;
+
+       // GUI
+       private static MainActivity mThis = null;
+       private ScanView mScanView;
+       private Intent mDeviceIntent;
+       private static final int STATUS_DURATION = 5;
+
+       // BLE management
+       private boolean mBtAdapterEnabled = false;
+       private boolean mBleSupported = true;
+       private boolean mScanning = false;
+       private int mNumDevs = 0;
+       private int mConnIndex = NO_DEVICE;
+       private List<BleDeviceInfo> mDeviceInfoList;
+       private static BluetoothManager mBluetoothManager;
+       private BluetoothAdapter mBtAdapter = null;
+       private BluetoothDevice mBluetoothDevice = null;
+       private BluetoothLeService mBluetoothLeService = null;
+       private IntentFilter mFilter;
+       private String[] mDeviceFilter = null;
+
+       // Housekeeping
+       private static final int NO_DEVICE = -1;
+       private boolean mInitialised = false;
+       SharedPreferences prefs = null;
+
+       public MainActivity() {
+               mThis = this;
+               mResourceFragmentPager = R.layout.fragment_pager;
+               mResourceIdPager = R.id.pager;
+       }
+
+       @Override
+       public void onCreate(Bundle savedInstanceState) {
+               // Start the application
+               requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+               super.onCreate(savedInstanceState);
+
+               prefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+               // Use this check to determine whether BLE is supported on the device. Then
+               // you can selectively disable BLE-related features.
+               if (!getPackageManager().hasSystemFeature(
+                   PackageManager.FEATURE_BLUETOOTH_LE)) {
+                       Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_LONG)
+                           .show();
+                       mBleSupported = false;
+               }
+
+               // Initializes a Bluetooth adapter. For API level 18 and above, get a
+               // reference to BluetoothAdapter through BluetoothManager.
+               mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+               mBtAdapter = mBluetoothManager.getAdapter();
+
+               // Checks if Bluetooth is supported on the device.
+               if (mBtAdapter == null) {
+                       Toast.makeText(this, R.string.bt_not_supported, Toast.LENGTH_LONG).show();
+                       mBleSupported = false;
+               }
+
+               // Initialize device list container and device filter
+               mDeviceInfoList = new ArrayList<BleDeviceInfo>();
+               Resources res = getResources();
+               mDeviceFilter = res.getStringArray(R.array.device_filter);
+
+               // Create the fragments and add them to the view pager and tabs
+               mScanView = new ScanView();
+               mSectionsPagerAdapter.addSection(mScanView, "BLE Device List");
+               
+               HelpView hw = new HelpView();
+               hw.setParameters("help_scan.html", R.layout.fragment_help, R.id.webpage);
+               mSectionsPagerAdapter.addSection(hw, "Help");
+
+               // Register the BroadcastReceiver
+               mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+               mFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
+               mFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
+       }
+
+       @Override
+       public void onDestroy() {
+               // Log.e(TAG,"onDestroy");
+               super.onDestroy();
+               if (mBluetoothLeService != null) {
+                       if (mScanning)
+                               scanLeDevice(false);
+                       unregisterReceiver(mReceiver);
+                       unbindService(mServiceConnection);
+                       mBluetoothLeService.close();
+                       mBluetoothLeService = null;
+               }
+               
+               mBtAdapter = null;
+               
+               // Clear cache
+               File cache = getCacheDir();
+               String path = cache.getPath();
+    try {
+           Runtime.getRuntime().exec(String.format("rm -rf %s", path));
+    } catch (IOException e) {
+           // TODO Auto-generated catch block
+           e.printStackTrace();
+    }
+       }
+
+       @Override
+       public boolean onOptionsItemSelected(MenuItem item) {
+               // Handle presses on the action bar items
+               switch (item.getItemId()) {
+               case android.R.id.home:
+                       onBackPressed();
+                       return true;
+               case R.id.opt_bt:
+                       onBluetooth();
+                       break;
+               case R.id.opt_e2e:
+                       onUrl(URL_FORUM);
+                       break;
+               case R.id.opt_sthome:
+                       onUrl(URL_STHOME);
+                       break;
+               case R.id.opt_license:
+                       onLicense();
+                       break;
+               case R.id.opt_about:
+                       onAbout();
+                       break;
+               case R.id.opt_exit:
+                       Toast.makeText(this, "Exit...", Toast.LENGTH_SHORT).show();
+                       finish();
+                       break;
+               default:
+                       return super.onOptionsItemSelected(item);
+               }
+               return true;
+       }
+
+       @Override
+       public boolean onCreateOptionsMenu(Menu menu) {
+               this.optionsMenu = menu;
+               // Inflate the menu items for use in the action bar
+               MenuInflater inflater = getMenuInflater();
+               inflater.inflate(R.menu.main_activity_actions, menu);
+               return super.onCreateOptionsMenu(menu);
+       }
+
+       private void onUrl(final Uri uri) {
+               Intent web = new Intent(Intent.ACTION_VIEW, uri);
+               startActivity(web);
+       }
+
+       private void onBluetooth() {
+               Intent settingsIntent = new Intent(
+                   android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
+               startActivity(settingsIntent);
+       }
+
+       private void onLicense() {
+               final Dialog dialog = new LicenseDialog(this);
+               dialog.show();
+       }
+
+       private void onAbout() {
+               final Dialog dialog = new AboutDialog(this);
+               dialog.show();
+       }
+
+       void onScanViewReady(View view) {
+               // Initial state of widgets
+               updateGuiState();
+
+               // License popup on first run
+               if (prefs.getBoolean("firstrun", true)) {
+                       onLicense();
+                       prefs.edit().putBoolean("firstrun", false).commit();
+               }
+
+               if (!mInitialised) {
+                       // Broadcast receiver
+                       registerReceiver(mReceiver, mFilter);
+                       mBtAdapterEnabled = mBtAdapter.isEnabled();
+                       if (mBtAdapterEnabled) {
+                               // Start straight away
+                               startBluetoothLeService();
+                       } else {
+                               // Request BT adapter to be turned on
+                               Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+                               startActivityForResult(enableIntent, REQ_ENABLE_BT);
+                       }
+                       mInitialised = true;
+               } else {
+                       mScanView.notifyDataSetChanged();
+               }
+       }
+
+       public void onBtnScan(View view) {
+               if (mScanning) {
+                       stopScan();
+               } else {
+                       startScan();
+               }
+       }
+
+       void onConnect() {
+               if (mNumDevs > 0) {
+                       int connState = mBluetoothManager.getConnectionState(mBluetoothDevice,
+                           BluetoothGatt.GATT);
+
+                       switch (connState) {
+                       case BluetoothGatt.STATE_CONNECTED:
+                               mBluetoothLeService.disconnect(null);
+                               break;
+                       case BluetoothGatt.STATE_DISCONNECTED:
+                               boolean ok = mBluetoothLeService.connect(mBluetoothDevice.getAddress());
+                               if (!ok) {
+                                       setError("Connect failed");
+                               }
+                               break;
+                       default:
+                               setError("Device busy (connecting/disconnecting)");
+                               break;
+                       }
+               }
+       }
+
+       private void startScan() {
+               // Start device discovery
+               if (mBleSupported) {
+                       mNumDevs = 0;
+                       mDeviceInfoList.clear();
+                       mScanView.notifyDataSetChanged();
+                       scanLeDevice(true);
+                       mScanView.updateGui(mScanning);
+                       if (!mScanning) {
+                               setError("Device discovery start failed");
+                               setBusy(false);
+                       }
+               } else {
+                       setError("BLE not supported on this device");
+               }
+
+       }
+
+       private void stopScan() {
+               mScanning = false;
+               mScanView.updateGui(false);
+               scanLeDevice(false);
+       }
+
+       private void startDeviceActivity() {
+               mDeviceIntent = new Intent(this, DeviceActivity.class);
+               mDeviceIntent.putExtra(DeviceActivity.EXTRA_DEVICE, mBluetoothDevice);
+               startActivityForResult(mDeviceIntent, REQ_DEVICE_ACT);
+       }
+
+       private void stopDeviceActivity() {
+               finishActivity(REQ_DEVICE_ACT);
+       }
+
+       public void onDeviceClick(final int pos) {
+
+               if (mScanning)
+                       stopScan();
+
+               setBusy(true);
+               mBluetoothDevice = mDeviceInfoList.get(pos).getBluetoothDevice();
+               if (mConnIndex == NO_DEVICE) {
+                       mScanView.setStatus("Connecting");
+                       mConnIndex = pos;
+                       onConnect();
+               } else {
+                       mScanView.setStatus("Disconnecting");
+                       if (mConnIndex != NO_DEVICE) {
+                               mBluetoothLeService.disconnect(mBluetoothDevice.getAddress());
+                       }
+               }
+       }
+
+       public void onScanTimeout() {
+               runOnUiThread(new Runnable() {
+                       public void run() {
+                               stopScan();
+                       }
+               });
+       }
+
+       public void onConnectTimeout() {
+               runOnUiThread(new Runnable() {
+                       public void run() {
+                               setError("Connection timed out");
+                       }
+               });
+               if (mConnIndex != NO_DEVICE) {
+                       mBluetoothLeService.disconnect(mBluetoothDevice.getAddress());
+                       mConnIndex = NO_DEVICE;
+               }
+       }
+
+       // ////////////////////////////////////////////////////////////////////////////////////////////////
+       //
+       // GUI methods
+       //
+       public void updateGuiState() {
+               boolean mBtEnabled = mBtAdapter.isEnabled();
+
+               if (mBtEnabled) {
+                       if (mScanning) {
+                               // BLE Host connected
+                               if (mConnIndex != NO_DEVICE) {
+                                       String txt = mBluetoothDevice.getName() + " connected";
+                                       mScanView.setStatus(txt);
+                               } else {
+                                       mScanView.setStatus(mNumDevs + " devices");
+                               }
+                       }
+               } else {
+                       mDeviceInfoList.clear();
+                       mScanView.notifyDataSetChanged();
+               }
+       }
+
+       private void setBusy(boolean f) {
+               mScanView.setBusy(f);
+       }
+
+       void setError(String txt) {
+               mScanView.setError(txt);
+               CustomToast.middleBottom(this, "Turning BT adapter off and on again may fix Android BLE stack problems");
+       }
+
+       private BleDeviceInfo createDeviceInfo(BluetoothDevice device, int rssi) {
+               BleDeviceInfo deviceInfo = new BleDeviceInfo(device, rssi);
+
+               return deviceInfo;
+       }
+
+       boolean checkDeviceFilter(String deviceName) {
+               if (deviceName == null)
+                       return false;
+
+               int n = mDeviceFilter.length;
+               if (n > 0) {
+                       boolean found = false;
+                       for (int i = 0; i < n && !found; i++) {
+                               found = deviceName.equals(mDeviceFilter[i]);
+                       }
+                       return found;
+               } else
+                       // Allow all devices if the device filter is empty
+                       return true;
+       }
+
+       private void addDevice(BleDeviceInfo device) {
+               mNumDevs++;
+               mDeviceInfoList.add(device);
+               mScanView.notifyDataSetChanged();
+               if (mNumDevs > 1)
+                       mScanView.setStatus(mNumDevs + " devices");
+               else
+                       mScanView.setStatus("1 device");
+       }
+
+       private boolean deviceInfoExists(String address) {
+               for (int i = 0; i < mDeviceInfoList.size(); i++) {
+                       if (mDeviceInfoList.get(i).getBluetoothDevice().getAddress()
+                           .equals(address)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       private BleDeviceInfo findDeviceInfo(BluetoothDevice device) {
+               for (int i = 0; i < mDeviceInfoList.size(); i++) {
+                       if (mDeviceInfoList.get(i).getBluetoothDevice().getAddress()
+                           .equals(device.getAddress())) {
+                               return mDeviceInfoList.get(i);
+                       }
+               }
+               return null;
+       }
+
+       private boolean scanLeDevice(boolean enable) {
+               if (enable) {
+                       mScanning = mBtAdapter.startLeScan(mLeScanCallback);
+               } else {
+                       mScanning = false;
+                       mBtAdapter.stopLeScan(mLeScanCallback);
+               }
+               return mScanning;
+       }
+
+       List<BleDeviceInfo> getDeviceInfoList() {
+               return mDeviceInfoList;
+       }
+
+       private void startBluetoothLeService() {
+               boolean f;
+
+               Intent bindIntent = new Intent(this, BluetoothLeService.class);
+               startService(bindIntent);
+               f = bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+               if (!f) {
+                       CustomToast.middleBottom(this, "Bind to BluetoothLeService failed");
+                       finish();
+               }
+       }
+
+       // Activity result handling
+       protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+               super.onActivityResult(requestCode, resultCode, data);
+
+               switch (requestCode) {
+               case REQ_DEVICE_ACT:
+                       // When the device activity has finished: disconnect the device
+                       if (mConnIndex != NO_DEVICE) {
+                               mBluetoothLeService.disconnect(mBluetoothDevice.getAddress());
+                       }
+                       break;
+
+               case REQ_ENABLE_BT:
+                       // When the request to enable Bluetooth returns
+                       if (resultCode == Activity.RESULT_OK) {
+
+                        &n