diff --git a/sample_app/libs/merge-1.0.1.jar b/sample_app/libs/merge-1.0.1.jar
new file mode 100644
index 0000000..fb49c15
Binary files /dev/null and b/sample_app/libs/merge-1.0.1.jar differ
diff --git a/sample_app/libs/sacklist-1.0.0.jar b/sample_app/libs/sacklist-1.0.0.jar
new file mode 100644
index 0000000..3a49a76
Binary files /dev/null and b/sample_app/libs/sacklist-1.0.0.jar differ
diff --git a/sample_app/res/layout/activity_details.xml b/sample_app/res/layout/activity_details.xml
index 011edb7..e853847 100644
--- a/sample_app/res/layout/activity_details.xml
+++ b/sample_app/res/layout/activity_details.xml
@@ -7,16 +7,9 @@
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
-
-
-
-
-
+
\ No newline at end of file
diff --git a/sample_app/res/layout/list_item_view_adrecord.xml b/sample_app/res/layout/list_item_view_adrecord.xml
new file mode 100644
index 0000000..ed0adc6
--- /dev/null
+++ b/sample_app/res/layout/list_item_view_adrecord.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/res/layout/list_item_view_device_info.xml b/sample_app/res/layout/list_item_view_device_info.xml
new file mode 100644
index 0000000..04ddfe7
--- /dev/null
+++ b/sample_app/res/layout/list_item_view_device_info.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/res/layout/list_item_view_header.xml b/sample_app/res/layout/list_item_view_header.xml
new file mode 100644
index 0000000..b218ade
--- /dev/null
+++ b/sample_app/res/layout/list_item_view_header.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/res/layout/list_item_view_ibeacon_details.xml b/sample_app/res/layout/list_item_view_ibeacon_details.xml
new file mode 100644
index 0000000..cd07cc9
--- /dev/null
+++ b/sample_app/res/layout/list_item_view_ibeacon_details.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/res/layout/list_item_view_rssi_info.xml b/sample_app/res/layout/list_item_view_rssi_info.xml
new file mode 100644
index 0000000..5b515cf
--- /dev/null
+++ b/sample_app/res/layout/list_item_view_rssi_info.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/res/layout/list_item_view_textview.xml b/sample_app/res/layout/list_item_view_textview.xml
new file mode 100644
index 0000000..1f00684
--- /dev/null
+++ b/sample_app/res/layout/list_item_view_textview.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/res/values/strings.xml b/sample_app/res/values/strings.xml
index 4c6cd43..5d57739 100644
--- a/sample_app/res/values/strings.xml
+++ b/sample_app/res/values/strings.xml
@@ -44,5 +44,12 @@
Bluetooth LE Scan Results (%s)
Please find attached the scan results.
Please select your email client:
+ iBeacon Data
+ Raw Ad Records
+ Scan Record
+ RSSI Info
+ Device Info
+ Invalid Device Data!
+ unknown
\ No newline at end of file
diff --git a/sample_app/res/values/styles.xml b/sample_app/res/values/styles.xml
index 6ce89c7..9cf5fd9 100644
--- a/sample_app/res/values/styles.xml
+++ b/sample_app/res/values/styles.xml
@@ -1,4 +1,4 @@
-
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample_app/src/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java b/sample_app/src/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java
index 2581279..75e91b7 100644
--- a/sample_app/src/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java
+++ b/sample_app/src/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java
@@ -1,32 +1,121 @@
package uk.co.alt236.btlescan.activities;
import java.util.Collection;
+import java.util.Locale;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData;
+import uk.co.alt236.bluetoothlelib.resolvers.CompanyIdentifierResolver;
import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.btlescan.R;
-import uk.co.alt236.btlescan.util.Constants;
-import android.app.Activity;
+import uk.co.alt236.btlescan.util.TimeFormatter;
+import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
+import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.ButterKnife;
-import butterknife.InjectView;
-public class DeviceDetailsActivity extends Activity{
- private static final String SECTION_LINE = "------------------------------";
+import com.commonsware.cwac.merge.MergeAdapter;
+
+public class DeviceDetailsActivity extends ListActivity{
public static final String EXTRA_DEVICE = "extra_device";
- @InjectView(R.id.tvDetails) TextView mTvDetails;
-
private BluetoothLeDevice mDevice;
+ private void appendAdRecordView(MergeAdapter adapter, String title, AdRecord record){
+ final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_adrecord, null);
+ final TextView tvString = (TextView) lt.findViewById(R.id.data_as_string);
+ final TextView tvArray = (TextView) lt.findViewById(R.id.data_as_array);
+ final TextView tvTitle = (TextView) lt.findViewById(R.id.title);
+
+ tvTitle.setText(title );
+ tvString.setText("'" + AdRecordUtils.getRecordDataAsString(record) + "'");
+ tvArray.setText("'" + ByteUtils.byteArrayToHexString(record.getData()) + "'");
+
+ adapter.addView(lt);
+ }
+
+ private void appendDeviceInfo(MergeAdapter adapter, BluetoothLeDevice device){
+ final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_device_info, null);
+ final TextView tvName = (TextView) lt.findViewById(R.id.deviceName);
+ final TextView tvAddress = (TextView) lt.findViewById(R.id.deviceAddress);
+ final TextView tvClass = (TextView) lt.findViewById(R.id.deviceClass);
+ final TextView tvBondingState = (TextView) lt.findViewById(R.id.deviceBondingState);
+
+ tvName.setText(device.getName());
+ tvAddress.setText(device.getAddress());
+ tvClass.setText(device.getBluetoothDeviceClassName());
+ tvBondingState.setText(device.getBluetoothDeviceBondState());
+
+ adapter.addView(lt);
+ }
+
+ private void appendHeader(MergeAdapter adapter, String title){
+ final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_header, null);
+ final TextView tvTitle = (TextView) lt.findViewById(R.id.title);
+ tvTitle.setText(title);
+
+ adapter.addView(lt);
+ }
+
+ private void appendIBeaconInfo(MergeAdapter adapter, IBeaconManufacturerData iBeaconData){
+ final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_ibeacon_details, null);
+ final TextView tvCompanyId = (TextView) lt.findViewById(R.id.companyId);
+ final TextView tvAdvert = (TextView) lt.findViewById(R.id.advertisement);
+ final TextView tvUUID = (TextView) lt.findViewById(R.id.uuid);
+ final TextView tvMajor = (TextView) lt.findViewById(R.id.major);
+ final TextView tvMinor = (TextView) lt.findViewById(R.id.minor);
+ final TextView tvTxPower = (TextView) lt.findViewById(R.id.txpower);
+
+ tvCompanyId.setText(
+ CompanyIdentifierResolver.getCompanyName(iBeaconData.getCompanyIdentifier(), getString(R.string.unknown))
+ + " (" + hexEncode(iBeaconData.getCompanyIdentifier()) + ")");
+ tvAdvert.setText(iBeaconData.getIBeaconAdvertisement() + " (" + hexEncode( iBeaconData.getIBeaconAdvertisement() ) + ")");
+ tvUUID.setText(iBeaconData.getUUID().toString());
+ tvMajor.setText(iBeaconData.getMajor() + " (" + hexEncode( iBeaconData.getMajor() ) + ")");
+ tvMinor.setText(iBeaconData.getMinor() + " (" + hexEncode( iBeaconData.getMinor() ) + ")");
+ tvTxPower.setText(iBeaconData.getCalibratedTxPower() + " (" + hexEncode( iBeaconData.getCalibratedTxPower() ) + ")");
+
+ adapter.addView(lt);
+ }
+
+ private void appendRssiInfo(MergeAdapter adapter, BluetoothLeDevice device){
+ final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_rssi_info, null);
+ final TextView tvFirstTimestamp = (TextView) lt.findViewById(R.id.firstTimestamp);
+ final TextView tvFirstRssi = (TextView) lt.findViewById(R.id.firstRssi);
+ final TextView tvLastTimestamp = (TextView) lt.findViewById(R.id.lastTimestamp);
+ final TextView tvLastRssi = (TextView) lt.findViewById(R.id.lastRssi);
+ final TextView tvRunningAverageRssi = (TextView) lt.findViewById(R.id.runningAverageRssi);
+
+ tvFirstTimestamp.setText(formatTime(device.getFirstTimestamp()));
+ tvFirstRssi.setText(formatRssi(device.getFirstRssi()));
+ tvLastTimestamp.setText(formatTime(device.getTimestamp()));
+ tvLastRssi.setText(formatRssi(device.getRssi()));
+ tvRunningAverageRssi.setText(formatRssi(device.getRunningAverageRssi()));
+
+ adapter.addView(lt);
+ }
+
+ private void appendSimpleText(MergeAdapter adapter, byte data[]){
+ appendSimpleText(adapter, ByteUtils.byteArrayToHexString(data));
+ }
+
+ private void appendSimpleText(MergeAdapter adapter, String data){
+ final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_textview, null);
+ final TextView tvData = (TextView) lt.findViewById(R.id.data);
+
+ tvData.setText(data);
+
+ adapter.addView(lt);
+ }
+
+
private String formatRssi(double rssi){
return getString(R.string.formatter_db, String.valueOf(rssi));
}
@@ -35,11 +124,6 @@ public class DeviceDetailsActivity extends Activity{
return getString(R.string.formatter_db, String.valueOf(rssi));
}
- private String formatTime(long time){
- return android.text.format.DateFormat.format(
- Constants.TIME_FORMAT, new java.util.Date(time)).toString();
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -62,11 +146,11 @@ public class DeviceDetailsActivity extends Activity{
switch (item.getItemId()) {
case R.id.menu_connect:
- final Intent intent = new Intent(this, DeviceControlActivity.class);
- intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, mDevice.getName());
- intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, mDevice.getAddress());
+ final Intent intent = new Intent(this, DeviceControlActivity.class);
+ intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, mDevice.getName());
+ intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, mDevice.getAddress());
- startActivity(intent);
+ startActivity(intent);
break;
}
@@ -74,85 +158,50 @@ public class DeviceDetailsActivity extends Activity{
}
private void pupulateDetails(BluetoothLeDevice device) {
- final StringBuilder sb = new StringBuilder();
+ final MergeAdapter adapter = new MergeAdapter();
if(device == null){
- append(sb, "Invalid Device Data!", null);
+ appendHeader(adapter, getString(R.string.header_device_info));
+ appendSimpleText(adapter, getString(R.string.invalid_device_data));
} else {
- append(sb, "Device Info", null);
- append(sb, SECTION_LINE, null);
- append(sb, "Device Name", device.getName());
- append(sb, "Device Address", device.getAddress());
+ appendHeader(adapter, getString(R.string.header_device_info));
+ appendDeviceInfo(adapter, device);
- append(sb, "", null);
- append(sb, "Device Class", device.getBluetoothDeviceClassName());
- append(sb, "Bonding State", device.getBluetoothDeviceBondState());
-
-
- append(sb, "", null);
- append(sb, "RSSI Info", null);
- append(sb, SECTION_LINE, null);
- append(sb, "First Timestamp", formatTime(device.getFirstTimestamp()));
- append(sb, "First RSSI", formatRssi(device.getFirstRssi()));
- append(sb, "Current Timestamp", formatTime(device.getTimestamp()));
- append(sb, "Current RSSI", formatRssi(device.getRssi()));
- append(sb, "Running Average RSSI", formatRssi(device.getRunningAverageRssi()));
-
- append(sb, "", null);
- append(sb, "Scan Record", null);
- append(sb, SECTION_LINE, null);
- append(sb, device.getScanRecord());
-
- append(sb, "", null);
- append(sb, "Raw Ad Records As String", null);
- append(sb, SECTION_LINE, null);
+ appendHeader(adapter, getString(R.string.header_rssi_info));
+ appendRssiInfo(adapter, device);
+ appendHeader(adapter, getString(R.string.header_scan_record));
+ appendSimpleText(adapter, device.getScanRecord());
final Collection adRecords = device.getAdRecordStore().getRecordsAsCollection();
+ if(adRecords.size() > 0){
+ appendHeader(adapter, getString(R.string.header_raw_ad_records));
- for(final AdRecord record : adRecords){
- append(sb, "#" +record.getType() + " " + record.getHumanReadableType(), null);
- append(sb, " As String: '" + AdRecordUtils.getRecordDataAsString(record) + "'", null);
- append(sb, " As Array : " + ByteUtils.byteArrayToHexString(record.getData()), null);
- append(sb, "", null);
+ for(final AdRecord record : adRecords){
+
+ appendAdRecordView(
+ adapter,
+ "#" + record.getType() + " " + record.getHumanReadableType(),
+ record);
+ }
}
- append(sb, "Additional", null);
- append(sb, SECTION_LINE, null);
- final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
- append(sb, "Is iBeacon", isIBeacon);
-
+ final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
if(isIBeacon){
final IBeaconManufacturerData iBeaconData = new IBeaconManufacturerData(device);
- append(sb, "Company ID", iBeaconData.getCompanyIdentifier() + " (" + Integer.toHexString( iBeaconData.getCompanyIdentifier() ) + ")");
- append(sb, "Advertisment", iBeaconData.getIBeaconAdvertisement() + " (" + Integer.toHexString( iBeaconData.getIBeaconAdvertisement() ) + ")");
- append(sb, "UUID", iBeaconData.getUUID().toString());
- append(sb, "Major", iBeaconData.getMajor() + " (" + Integer.toHexString( iBeaconData.getMajor() ) + ")");
- append(sb, "Minor", iBeaconData.getMinor() + " (" + Integer.toHexString( iBeaconData.getMinor() ) + ")");
- append(sb, "TX Power", iBeaconData.getCalibratedTxPower() + " (" + Integer.toHexString( iBeaconData.getCalibratedTxPower() ) + ")");
+ appendHeader(adapter, getString(R.string.header_ibeacon_data));
+ appendIBeaconInfo(adapter, iBeaconData);
}
+
}
-
- mTvDetails.setText(sb.toString());
+ getListView().setAdapter(adapter);
}
- private static void append(StringBuilder sb, byte[] value){
- append(sb, ByteUtils.byteArrayToHexString(value), null);
+ private static String formatTime(long time){
+ return TimeFormatter.getIsoDateTime(time);
}
- private static void append(StringBuilder sb, String label, boolean value) {
- append(sb, label, String.valueOf(value));
- }
-
- private static void append(StringBuilder sb, String label, String value){
- if(value != null){
- sb.append("\u2022" + padRight(label, 10) +":\t" + value + "\n");
- } else {
- sb.append(label + "\n");
- }
- }
-
- public static String padRight(String s, int n) {
- return String.format("%1$-" + n + "s", s);
+ private static String hexEncode(int integer){
+ return "0x" + Integer.toHexString(integer).toUpperCase(Locale.US);
}
}