Updated the UI to support the runing average

This commit is contained in:
Alexandros Schillings
2014-03-18 15:23:14 +00:00
parent 83ee1eab66
commit e2294ca926
8 changed files with 103 additions and 79 deletions
+3 -8
View File
@@ -17,11 +17,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="top"
android:orientation="horizontal" > android:orientation="horizontal" >
<ImageView <ImageView
android:id="@+id/device_icon" android:id="@+id/device_icon"
android:paddingTop="5dp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingRight="5dp" android:paddingRight="5dp"
@@ -57,12 +58,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="12sp" android:textSize="12sp"
android:typeface="monospace" /> android:typeface="monospace" />
</GridLayout>
<GridLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:columnCount="4" >
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -82,7 +77,6 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp" android:paddingRight="5dp"
android:text="@string/label_rssi" android:text="@string/label_rssi"
android:textSize="12sp" android:textSize="12sp"
@@ -100,6 +94,7 @@
android:id="@+id/ibeacon_section" android:id="@+id/ibeacon_section"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/light_gray"
android:columnCount="4" > android:columnCount="4" >
<!-- ROW 1 --> <!-- ROW 1 -->
+3
View File
@@ -0,0 +1,3 @@
<resources>
<color name="light_gray">#e0e0e0</color>
</resources>
+6
View File
@@ -11,11 +11,17 @@
<string name="no_data">No data</string> <string name="no_data">No data</string>
<string name="unknown_device">Unknown Device</string> <string name="unknown_device">Unknown Device</string>
<!-- Formatters -->
<string name="formatter_meters">%sm</string>
<string name="formatter_db">%sdb</string>
<!-- Menu items --> <!-- Menu items -->
<string name="menu_connect">Connect</string> <string name="menu_connect">Connect</string>
<string name="menu_disconnect">Disconnect</string> <string name="menu_disconnect">Disconnect</string>
<string name="menu_scan">Scan</string> <string name="menu_scan">Scan</string>
<string name="menu_stop">Stop</string> <string name="menu_stop">Stop</string>
<!-- List Items -->
<string name="label_distance">Distance:</string> <string name="label_distance">Distance:</string>
<string name="label_tx_power">TX Power:</string> <string name="label_tx_power">TX Power:</string>
<string name="label_minor">Minor:</string> <string name="label_minor">Minor:</string>
@@ -9,6 +9,7 @@ import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
import uk.co.alt236.bluetoothlelib.util.ByteUtils; import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils; import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.btlescan.R; import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.Constants;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.widget.TextView; import android.widget.TextView;
@@ -16,6 +17,7 @@ import butterknife.ButterKnife;
import butterknife.InjectView; import butterknife.InjectView;
public class DetailsActivity extends Activity{ public class DetailsActivity extends Activity{
private static final String SECTION_LINE = "------------------------------";
public static final String EXTRA_DEVICE = "extra_device"; public static final String EXTRA_DEVICE = "extra_device";
@InjectView(R.id.tvDetails) TextView mTvDetails; @InjectView(R.id.tvDetails) TextView mTvDetails;
@@ -33,6 +35,19 @@ public class DetailsActivity extends Activity{
pupulateDetails(mDevice); pupulateDetails(mDevice);
} }
private String formatTime(long time){
return android.text.format.DateFormat.format(
Constants.TIME_FORMAT, new java.util.Date(time)).toString();
}
private String formatRssi(int rssi){
return getString(R.string.formatter_db, String.valueOf(rssi));
}
private String formatRssi(double rssi){
return getString(R.string.formatter_db, String.valueOf(rssi));
}
private void pupulateDetails(BluetoothLeDevice device) { private void pupulateDetails(BluetoothLeDevice device) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@@ -46,14 +61,24 @@ public class DetailsActivity extends Activity{
append(sb, "Device Class", device.getBluetoothDeviceClassName()); append(sb, "Device Class", device.getBluetoothDeviceClassName());
append(sb, "Bonding State", device.getBluetoothDeviceBondState()); 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, "", null);
append(sb, "Scan Record", null); append(sb, "Scan Record", null);
append(sb, "-----------------", null); append(sb, SECTION_LINE, null);
append(sb, device.getScanRecord()); append(sb, device.getScanRecord());
append(sb, "", null); append(sb, "", null);
append(sb, "Raw Ad Records As String", null); append(sb, "Raw Ad Records As String", null);
append(sb, "-----------------", null); append(sb, SECTION_LINE, null);
final Collection<AdRecord> adRecords = device.getAdRecordStore().getRecordsAsCollection(); final Collection<AdRecord> adRecords = device.getAdRecordStore().getRecordsAsCollection();
@@ -65,14 +90,14 @@ public class DetailsActivity extends Activity{
} }
append(sb, "Additional", null); append(sb, "Additional", null);
append(sb, "-----------------", null); append(sb, SECTION_LINE, null);
final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device); final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
append(sb, "Is iBeacon", isIBeacon); append(sb, "Is iBeacon", isIBeacon);
if(isIBeacon){ if(isIBeacon){
final IBeaconManufacturerData iBeaconData = new IBeaconManufacturerData(device); final IBeaconManufacturerData iBeaconData = new IBeaconManufacturerData(device);
append(sb, "Company ID", iBeaconData.getCompanyIdentifier() + " (" + Integer.toHexString( iBeaconData.getCompanyIdentifier() ) + ")"); append(sb, "Company ID", iBeaconData.getCompanyIdentifier() + " (" + Integer.toHexString( iBeaconData.getCompanyIdentifier() ) + ")");
append(sb, "iBeacon Advertisment", iBeaconData.getIBeaconAdvertisement() + " (" + Integer.toHexString( iBeaconData.getIBeaconAdvertisement() ) + ")"); append(sb, "Advertisment", iBeaconData.getIBeaconAdvertisement() + " (" + Integer.toHexString( iBeaconData.getIBeaconAdvertisement() ) + ")");
append(sb, "UUID", iBeaconData.getUUID().toString()); append(sb, "UUID", iBeaconData.getUUID().toString());
append(sb, "Major", iBeaconData.getMajor() + " (" + Integer.toHexString( iBeaconData.getMajor() ) + ")"); append(sb, "Major", iBeaconData.getMajor() + " (" + Integer.toHexString( iBeaconData.getMajor() ) + ")");
append(sb, "Minor", iBeaconData.getMinor() + " (" + Integer.toHexString( iBeaconData.getMinor() ) + ")"); append(sb, "Minor", iBeaconData.getMinor() + " (" + Integer.toHexString( iBeaconData.getMinor() ) + ")");
@@ -91,17 +116,25 @@ public class DetailsActivity extends Activity{
append(sb, label, String.valueOf(value)); append(sb, label, String.valueOf(value));
} }
private static void append(StringBuilder sb, String label, int value) { // private static void append(StringBuilder sb, String label, double value) {
append(sb, label, String.valueOf(value)); // append(sb, label, String.valueOf(value));
} // }
//
// private static void append(StringBuilder sb, String label, int value) {
// append(sb, label, String.valueOf(value));
// }
//
// private static void append(StringBuilder sb, String label, long value) {
// append(sb, label, String.valueOf(value));
// }
private static void append(StringBuilder sb, String label, long value) { public static String padRight(String s, int n) {
append(sb, label, String.valueOf(value)); return String.format("%1$-" + n + "s", s);
} }
private static void append(StringBuilder sb, String label, String value){ private static void append(StringBuilder sb, String label, String value){
if(value != null){ if(value != null){
sb.append("\u2022" + label +":\t" + value + "\n"); sb.append("\u2022" + padRight(label, 10) +":\t" + value + "\n");
} else { } else {
sb.append(label + "\n"); sb.append(label + "\n");
} }
@@ -1,11 +1,9 @@
package uk.co.alt236.btlescan.activities; package uk.co.alt236.btlescan.activities;
import java.util.ArrayList;
import java.util.List;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice; import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.btlescan.R; import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.adapters.LeDeviceListAdapter; import uk.co.alt236.btlescan.adapters.LeDeviceListAdapter;
import uk.co.alt236.btlescan.containers.BluetoothLeDeviceStore;
import uk.co.alt236.btlescan.util.BluetoothLeScanner; import uk.co.alt236.btlescan.util.BluetoothLeScanner;
import uk.co.alt236.btlescan.util.BluetoothUtils; import uk.co.alt236.btlescan.util.BluetoothUtils;
import uk.co.alt236.btlescan.views.RadarView; import uk.co.alt236.btlescan.views.RadarView;
@@ -30,10 +28,7 @@ public class MainActivity extends ListActivity {
private BluetoothUtils mBluetoothUtils; private BluetoothUtils mBluetoothUtils;
private BluetoothLeScanner mScanner; private BluetoothLeScanner mScanner;
private LeDeviceListAdapter mLeDeviceListAdapter; private LeDeviceListAdapter mLeDeviceListAdapter;
private List<BluetoothLeDevice> mDeviceList; private BluetoothLeDeviceStore mDeviceStore;
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override @Override
@@ -44,17 +39,18 @@ public class MainActivity extends ListActivity {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
mLeDeviceListAdapter.addDevice(deviceLe); mDeviceStore.addDevice(deviceLe);
mLeDeviceListAdapter.clear();
mLeDeviceListAdapter.addAll(mDeviceStore.getDeviceList());
mLeDeviceListAdapter.notifyDataSetChanged(); mLeDeviceListAdapter.notifyDataSetChanged();
} }
}); });
} }
}; };
@Override @Override
protected void onListItemClick(ListView l, View v, int position, long id) { protected void onListItemClick(ListView l, View v, int position, long id) {
final BluetoothLeDevice device = mLeDeviceListAdapter.getDevice(position); final BluetoothLeDevice device = mLeDeviceListAdapter.getItem(position);
if (device == null) return; if (device == null) return;
@@ -69,8 +65,8 @@ public class MainActivity extends ListActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
ButterKnife.inject(this); ButterKnife.inject(this);
mDeviceList = new ArrayList<BluetoothLeDevice>();
mDeviceStore = new BluetoothLeDeviceStore();
mBluetoothUtils = new BluetoothUtils(this); mBluetoothUtils = new BluetoothUtils(this);
mScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils); mScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils);
} }
@@ -134,8 +130,9 @@ public class MainActivity extends ListActivity {
private void startScan(){ private void startScan(){
final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn(); final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn();
final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported(); final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
mDeviceStore.clear();
mLeDeviceListAdapter = new LeDeviceListAdapter(this); mLeDeviceListAdapter = new LeDeviceListAdapter(this, mDeviceStore.getDeviceList());
setListAdapter(mLeDeviceListAdapter); setListAdapter(mLeDeviceListAdapter);
mBluetoothUtils.askUserToEnableBluetoothIfNeeded(); mBluetoothUtils.askUserToEnableBluetoothIfNeeded();
@@ -1,60 +1,38 @@
package uk.co.alt236.btlescan.adapters; package uk.co.alt236.btlescan.adapters;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice; import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.device.IBeaconDevice; import uk.co.alt236.bluetoothlelib.device.IBeaconDevice;
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils; import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.btlescan.R; import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.Constants;
import android.app.Activity; import android.app.Activity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
// Adapter for holding devices found through scanning. // Adapter for holding devices found through scanning.
public class LeDeviceListAdapter extends BaseAdapter { public class LeDeviceListAdapter extends ArrayAdapter<BluetoothLeDevice> {
private static final DecimalFormat DOUBLE_TWO_DIGIT_ACCURACY = new DecimalFormat("#.##");
private static final String TIME_FORMAT = "yyyy-MM-dd hh:mm:ss";
private final List<BluetoothLeDevice> mLeDevices;
private final LayoutInflater mInflator; private final LayoutInflater mInflator;
private final Activity mActivity;
public LeDeviceListAdapter(Activity activity) { public LeDeviceListAdapter(Activity activity, List<BluetoothLeDevice> list) {
super(); super(activity, R.layout.list_item_device, list);
mLeDevices = new ArrayList<BluetoothLeDevice>();
mInflator = activity.getLayoutInflater(); mInflator = activity.getLayoutInflater();
mActivity = activity;
} }
public void addDevice(BluetoothLeDevice device) { // public void addDevice(BluetoothLeDevice device) {
final int position = mLeDevices.indexOf(device); // final int position = mLeDevices.indexOf(device);
if(position == -1){ // if(position == -1){
mLeDevices.add(device); // mLeDevices.add(device);
} else { // } else {
mLeDevices.set(position, device); // mLeDevices.set(position, device);
} // }
} // }
public BluetoothLeDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
@Override
public int getCount() {
return mLeDevices.size();
}
@Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
@Override @Override
public long getItemId(int i) { public long getItemId(int i) {
@@ -85,7 +63,7 @@ public class LeDeviceListAdapter extends BaseAdapter {
viewHolder = (ViewHolder) view.getTag(); viewHolder = (ViewHolder) view.getTag();
} }
final BluetoothLeDevice device = mLeDevices.get(i); final BluetoothLeDevice device = getItem(i);
final String deviceName = device.getName(); final String deviceName = device.getName();
final double rssi = device.getRssi(); final double rssi = device.getRssi();
@@ -96,11 +74,8 @@ public class LeDeviceListAdapter extends BaseAdapter {
} }
if (IBeaconUtils.isThisAnIBeacon(device)){ if (IBeaconUtils.isThisAnIBeacon(device)){
// Alternatively you can just call
// IBeaconManufacturerData data = new IBeaconManufacturerData(device);
final IBeaconDevice iBeacon = new IBeaconDevice(device); final IBeaconDevice iBeacon = new IBeaconDevice(device);
final double accuracy = iBeacon.getAccuracy(); final String accuracy = Constants.DOUBLE_TWO_DIGIT_ACCURACY.format(iBeacon.getAccuracy());
viewHolder.deviceIcon.setImageResource(R.drawable.ic_device_ibeacon); viewHolder.deviceIcon.setImageResource(R.drawable.ic_device_ibeacon);
viewHolder.ibeaconSection.setVisibility(View.VISIBLE); viewHolder.ibeaconSection.setVisibility(View.VISIBLE);
@@ -108,17 +83,22 @@ public class LeDeviceListAdapter extends BaseAdapter {
viewHolder.ibeaconMinor.setText(String.valueOf(iBeacon.getMinor())); viewHolder.ibeaconMinor.setText(String.valueOf(iBeacon.getMinor()));
viewHolder.ibeaconTxPower.setText(String.valueOf(iBeacon.getCalibratedTxPower())); viewHolder.ibeaconTxPower.setText(String.valueOf(iBeacon.getCalibratedTxPower()));
viewHolder.ibeaconUUID.setText(iBeacon.getUUID()); viewHolder.ibeaconUUID.setText(iBeacon.getUUID());
viewHolder.ibeaconDistance.setText(DOUBLE_TWO_DIGIT_ACCURACY.format(accuracy) + "m"); viewHolder.ibeaconDistance.setText(
mActivity.getString(R.string.formatter_meters, accuracy));
viewHolder.ibeaconDistanceDescriptor.setText(iBeacon.getDistanceDescriptor().toString()); viewHolder.ibeaconDistanceDescriptor.setText(iBeacon.getDistanceDescriptor().toString());
} else { } else {
viewHolder.deviceIcon.setImageResource(R.drawable.ic_bluetooth); viewHolder.deviceIcon.setImageResource(R.drawable.ic_bluetooth);
viewHolder.ibeaconSection.setVisibility(View.GONE); viewHolder.ibeaconSection.setVisibility(View.GONE);
} }
final String rssiString = mActivity.getString(R.string.formatter_db, String.valueOf(rssi));
final String runningAverageRssiString = mActivity.getString(R.string.formatter_db, String.valueOf(device.getRunningAverageRssi()));
viewHolder.deviceLastUpdated.setText( viewHolder.deviceLastUpdated.setText(
android.text.format.DateFormat.format(TIME_FORMAT, new java.util.Date(device.getTimestamp()))); android.text.format.DateFormat.format(
Constants.TIME_FORMAT, new java.util.Date(device.getTimestamp())));
viewHolder.deviceAddress.setText(device.getAddress()); viewHolder.deviceAddress.setText(device.getAddress());
viewHolder.deviceRssi.setText(String.valueOf(rssi) + "db"); viewHolder.deviceRssi.setText(rssiString + " / " + runningAverageRssiString);
return view; return view;
} }
@@ -1,4 +1,4 @@
package uk.co.alt236.btlescan.util; package uk.co.alt236.btlescan.containers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -12,23 +12,26 @@ import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
public class BluetoothLeDeviceStore { public class BluetoothLeDeviceStore {
private final Map<String, BluetoothLeDevice> mDeviceMap; private final Map<String, BluetoothLeDevice> mDeviceMap;
public BluetoothLeDeviceStore(){ public BluetoothLeDeviceStore(){
mDeviceMap = new HashMap<String, BluetoothLeDevice>(); mDeviceMap = new HashMap<String, BluetoothLeDevice>();
} }
public void addDevice(BluetoothLeDevice device){ public void addDevice(BluetoothLeDevice device){
if(mDeviceMap.containsKey(device.getAddress())){ if(mDeviceMap.containsKey(device.getAddress())){
mDeviceMap.get(device.getAddress()).updateRssiReading(device.getTimestamp(), device.getRssi());
} else { } else {
mDeviceMap.put(device.getAddress(), device); mDeviceMap.put(device.getAddress(), device);
} }
} }
public void clear(){
mDeviceMap.clear();
}
public List<BluetoothLeDevice> getDeviceList(){ public List<BluetoothLeDevice> getDeviceList(){
final List<BluetoothLeDevice> methodResult = new ArrayList<BluetoothLeDevice>(mDeviceMap.values()); final List<BluetoothLeDevice> methodResult = new ArrayList<BluetoothLeDevice>(mDeviceMap.values());
Collections.sort(methodResult, new Comparator<BluetoothLeDevice>() { Collections.sort(methodResult, new Comparator<BluetoothLeDevice>() {
@Override @Override
@@ -37,7 +40,6 @@ public class BluetoothLeDeviceStore {
} }
}); });
return methodResult; return methodResult;
} }
} }
@@ -0,0 +1,8 @@
package uk.co.alt236.btlescan.util;
import java.text.DecimalFormat;
public class Constants {
public static final DecimalFormat DOUBLE_TWO_DIGIT_ACCURACY = new DecimalFormat("#.##");
public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
}