Full code reformat
This commit is contained in:
@@ -1,43 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<manifest
|
||||
package="uk.co.alt236.btlescan"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="3"
|
||||
android:versionName="0.0.3" >
|
||||
android:versionName="0.0.3">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
android:targetSdkVersion="18"/>
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.bluetooth_le"
|
||||
android:required="false" />
|
||||
android:required="false"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name="uk.co.alt236.btlescan.activities.MainActivity"
|
||||
android:label="@string/app_name" >
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="uk.co.alt236.btlescan.activities.DeviceDetailsActivity"
|
||||
android:label="@string/app_name" >
|
||||
android:label="@string/app_name">
|
||||
</activity>
|
||||
<activity android:name="uk.co.alt236.btlescan.activities.DeviceControlActivity" />
|
||||
<activity android:name="uk.co.alt236.btlescan.activities.DeviceControlActivity"/>
|
||||
|
||||
<service
|
||||
android:name="uk.co.alt236.btlescan.services.BluetoothLeService"
|
||||
android:enabled="true" />
|
||||
android:enabled="true"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
+321
-322
@@ -16,16 +16,6 @@
|
||||
|
||||
package uk.co.alt236.btlescan.activities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.resolvers.GattAttributeResolver;
|
||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||
import uk.co.alt236.btlescan.R;
|
||||
import uk.co.alt236.btlescan.services.BluetoothLeService;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
@@ -44,8 +34,19 @@ import android.view.View;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.SimpleExpandableListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.resolvers.GattAttributeResolver;
|
||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||
import uk.co.alt236.btlescan.R;
|
||||
import uk.co.alt236.btlescan.services.BluetoothLeService;
|
||||
|
||||
/**
|
||||
* For a given BLE device, this Activity provides the user interface to connect, display data,
|
||||
@@ -54,358 +55,356 @@ import butterknife.InjectView;
|
||||
* Bluetooth LE API.
|
||||
*/
|
||||
public class DeviceControlActivity extends Activity {
|
||||
private final static String TAG = DeviceControlActivity.class.getSimpleName();
|
||||
public static final String EXTRA_DEVICE = "extra_device";
|
||||
public static final String EXTRA_DEVICE = "extra_device";
|
||||
private final static String TAG = DeviceControlActivity.class.getSimpleName();
|
||||
private static final String LIST_NAME = "NAME";
|
||||
private static final String LIST_UUID = "UUID";
|
||||
@InjectView(R.id.gatt_services_list)
|
||||
ExpandableListView mGattServicesList;
|
||||
@InjectView(R.id.connection_state)
|
||||
TextView mConnectionState;
|
||||
@InjectView(R.id.uuid)
|
||||
TextView mGattUUID;
|
||||
@InjectView(R.id.description)
|
||||
TextView mGattUUIDDesc;
|
||||
@InjectView(R.id.data_as_string)
|
||||
TextView mDataAsString;
|
||||
@InjectView(R.id.data_as_array)
|
||||
TextView mDataAsArray;
|
||||
private BluetoothGattCharacteristic mNotifyCharacteristic;
|
||||
private BluetoothLeService mBluetoothLeService;
|
||||
private List<List<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<List<BluetoothGattCharacteristic>>();
|
||||
// If a given GATT characteristic is selected, check for supported features. This sample
|
||||
// demonstrates 'Read' and 'Notify' features. See
|
||||
// http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete
|
||||
// list of supported characteristic features.
|
||||
private final ExpandableListView.OnChildClickListener servicesListClickListner = new ExpandableListView.OnChildClickListener() {
|
||||
@Override
|
||||
public boolean onChildClick(final ExpandableListView parent, final View v, final int groupPosition, final int childPosition, final long id) {
|
||||
if (mGattCharacteristics != null) {
|
||||
final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition);
|
||||
final int charaProp = characteristic.getProperties();
|
||||
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
|
||||
// If there is an active notification on a characteristic, clear
|
||||
// it first so it doesn't update the data field on the user interface.
|
||||
if (mNotifyCharacteristic != null) {
|
||||
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
|
||||
mNotifyCharacteristic = null;
|
||||
}
|
||||
mBluetoothLeService.readCharacteristic(characteristic);
|
||||
}
|
||||
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
|
||||
mNotifyCharacteristic = characteristic;
|
||||
mBluetoothLeService.setCharacteristicNotification(characteristic, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
private String mDeviceAddress;
|
||||
// Code to manage Service lifecycle.
|
||||
private final ServiceConnection mServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(final ComponentName componentName, final IBinder service) {
|
||||
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
|
||||
if (!mBluetoothLeService.initialize()) {
|
||||
Log.e(TAG, "Unable to initialize Bluetooth");
|
||||
finish();
|
||||
}
|
||||
// Automatically connects to the device upon successful start-up initialization.
|
||||
mBluetoothLeService.connect(mDeviceAddress);
|
||||
}
|
||||
|
||||
private static final String LIST_NAME = "NAME";
|
||||
private static final String LIST_UUID = "UUID";
|
||||
@Override
|
||||
public void onServiceDisconnected(final ComponentName componentName) {
|
||||
mBluetoothLeService = null;
|
||||
}
|
||||
};
|
||||
private String mDeviceName;
|
||||
private boolean mConnected = false;
|
||||
private String mExportString;
|
||||
// Handles various events fired by the Service.
|
||||
// ACTION_GATT_CONNECTED: connected to a GATT server.
|
||||
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
|
||||
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
|
||||
// ACTION_DATA_AVAILABLE: received data from the device.
|
||||
// this can be a result of read or notification operations.
|
||||
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
|
||||
mConnected = true;
|
||||
updateConnectionState(R.string.connected);
|
||||
invalidateOptionsMenu();
|
||||
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
|
||||
mConnected = false;
|
||||
updateConnectionState(R.string.disconnected);
|
||||
invalidateOptionsMenu();
|
||||
clearUI();
|
||||
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
|
||||
// Show all the supported services and characteristics on the user interface.
|
||||
displayGattServices(mBluetoothLeService.getSupportedGattServices());
|
||||
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
|
||||
final String noData = getString(R.string.no_data);
|
||||
final String uuid = intent.getStringExtra(BluetoothLeService.EXTRA_UUID_CHAR);
|
||||
final byte[] dataArr = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA_RAW);
|
||||
|
||||
private BluetoothGattCharacteristic mNotifyCharacteristic;
|
||||
private BluetoothLeService mBluetoothLeService;
|
||||
private List<List<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<List<BluetoothGattCharacteristic>>();
|
||||
private String mDeviceAddress;
|
||||
private String mDeviceName;
|
||||
mGattUUID.setText(tryString(uuid, noData));
|
||||
mGattUUIDDesc.setText(GattAttributeResolver.getAttributeName(uuid, getString(R.string.unknown)));
|
||||
mDataAsArray.setText(ByteUtils.byteArrayToHexString(dataArr));
|
||||
mDataAsString.setText(new String(dataArr));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@InjectView(R.id.gatt_services_list) ExpandableListView mGattServicesList;
|
||||
@InjectView(R.id.connection_state) TextView mConnectionState;
|
||||
private void clearUI() {
|
||||
mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
|
||||
mGattUUID.setText(R.string.no_data);
|
||||
mGattUUIDDesc.setText(R.string.no_data);
|
||||
mDataAsArray.setText(R.string.no_data);
|
||||
mDataAsString.setText(R.string.no_data);
|
||||
}
|
||||
|
||||
@InjectView(R.id.uuid) TextView mGattUUID;
|
||||
@InjectView(R.id.description) TextView mGattUUIDDesc;
|
||||
@InjectView(R.id.data_as_string) TextView mDataAsString;
|
||||
@InjectView(R.id.data_as_array) TextView mDataAsArray;
|
||||
// Demonstrates how to iterate through the supported GATT Services/Characteristics.
|
||||
// In this sample, we populate the data structure that is bound to the ExpandableListView
|
||||
// on the UI.
|
||||
private void displayGattServices(final List<BluetoothGattService> gattServices) {
|
||||
if (gattServices == null) return;
|
||||
generateExportString(gattServices);
|
||||
|
||||
private boolean mConnected = false;
|
||||
private String mExportString;
|
||||
String uuid = null;
|
||||
final String unknownServiceString = getResources().getString(R.string.unknown_service);
|
||||
final String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
|
||||
final List<Map<String, String>> gattServiceData = new ArrayList<Map<String, String>>();
|
||||
final List<List<Map<String, String>>> gattCharacteristicData = new ArrayList<List<Map<String, String>>>();
|
||||
mGattCharacteristics = new ArrayList<List<BluetoothGattCharacteristic>>();
|
||||
|
||||
// Code to manage Service lifecycle.
|
||||
private final ServiceConnection mServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(final ComponentName componentName, final IBinder service) {
|
||||
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
|
||||
if (!mBluetoothLeService.initialize()) {
|
||||
Log.e(TAG, "Unable to initialize Bluetooth");
|
||||
finish();
|
||||
}
|
||||
// Automatically connects to the device upon successful start-up initialization.
|
||||
mBluetoothLeService.connect(mDeviceAddress);
|
||||
}
|
||||
// Loops through available GATT Services.
|
||||
for (final BluetoothGattService gattService : gattServices) {
|
||||
final Map<String, String> currentServiceData = new HashMap<String, String>();
|
||||
uuid = gattService.getUuid().toString();
|
||||
currentServiceData.put(LIST_NAME, GattAttributeResolver.getAttributeName(uuid, unknownServiceString));
|
||||
currentServiceData.put(LIST_UUID, uuid);
|
||||
gattServiceData.add(currentServiceData);
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(final ComponentName componentName) {
|
||||
mBluetoothLeService = null;
|
||||
}
|
||||
};
|
||||
final List<Map<String, String>> gattCharacteristicGroupData = new ArrayList<Map<String, String>>();
|
||||
final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
|
||||
final List<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();
|
||||
|
||||
// Handles various events fired by the Service.
|
||||
// ACTION_GATT_CONNECTED: connected to a GATT server.
|
||||
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
|
||||
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
|
||||
// ACTION_DATA_AVAILABLE: received data from the device.
|
||||
// this can be a result of read or notification operations.
|
||||
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
|
||||
mConnected = true;
|
||||
updateConnectionState(R.string.connected);
|
||||
invalidateOptionsMenu();
|
||||
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
|
||||
mConnected = false;
|
||||
updateConnectionState(R.string.disconnected);
|
||||
invalidateOptionsMenu();
|
||||
clearUI();
|
||||
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
|
||||
// Show all the supported services and characteristics on the user interface.
|
||||
displayGattServices(mBluetoothLeService.getSupportedGattServices());
|
||||
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
|
||||
final String noData = getString(R.string.no_data);
|
||||
final String uuid = intent.getStringExtra(BluetoothLeService.EXTRA_UUID_CHAR);
|
||||
final byte[] dataArr = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA_RAW);
|
||||
// Loops through available Characteristics.
|
||||
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
|
||||
charas.add(gattCharacteristic);
|
||||
final Map<String, String> currentCharaData = new HashMap<String, String>();
|
||||
uuid = gattCharacteristic.getUuid().toString();
|
||||
currentCharaData.put(LIST_NAME, GattAttributeResolver.getAttributeName(uuid, unknownCharaString));
|
||||
currentCharaData.put(LIST_UUID, uuid);
|
||||
gattCharacteristicGroupData.add(currentCharaData);
|
||||
}
|
||||
|
||||
mGattUUID.setText(tryString(uuid, noData));
|
||||
mGattUUIDDesc.setText(GattAttributeResolver.getAttributeName(uuid, getString(R.string.unknown)));
|
||||
mDataAsArray.setText(ByteUtils.byteArrayToHexString(dataArr));
|
||||
mDataAsString.setText(new String(dataArr));
|
||||
}
|
||||
}
|
||||
};
|
||||
mGattCharacteristics.add(charas);
|
||||
gattCharacteristicData.add(gattCharacteristicGroupData);
|
||||
}
|
||||
|
||||
// If a given GATT characteristic is selected, check for supported features. This sample
|
||||
// demonstrates 'Read' and 'Notify' features. See
|
||||
// http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete
|
||||
// list of supported characteristic features.
|
||||
private final ExpandableListView.OnChildClickListener servicesListClickListner = new ExpandableListView.OnChildClickListener() {
|
||||
@Override
|
||||
public boolean onChildClick(final ExpandableListView parent, final View v, final int groupPosition, final int childPosition, final long id) {
|
||||
if (mGattCharacteristics != null) {
|
||||
final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition);
|
||||
final int charaProp = characteristic.getProperties();
|
||||
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
|
||||
// If there is an active notification on a characteristic, clear
|
||||
// it first so it doesn't update the data field on the user interface.
|
||||
if (mNotifyCharacteristic != null) {
|
||||
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
|
||||
mNotifyCharacteristic = null;
|
||||
}
|
||||
mBluetoothLeService.readCharacteristic(characteristic);
|
||||
}
|
||||
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
|
||||
mNotifyCharacteristic = characteristic;
|
||||
mBluetoothLeService.setCharacteristicNotification(characteristic, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
final SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(
|
||||
this,
|
||||
gattServiceData,
|
||||
android.R.layout.simple_expandable_list_item_2,
|
||||
new String[]{LIST_NAME, LIST_UUID},
|
||||
new int[]{android.R.id.text1, android.R.id.text2},
|
||||
gattCharacteristicData,
|
||||
android.R.layout.simple_expandable_list_item_2,
|
||||
new String[]{LIST_NAME, LIST_UUID},
|
||||
new int[]{android.R.id.text1, android.R.id.text2}
|
||||
);
|
||||
|
||||
private void clearUI() {
|
||||
mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
|
||||
mGattUUID.setText(R.string.no_data);
|
||||
mGattUUIDDesc.setText(R.string.no_data);
|
||||
mDataAsArray.setText(R.string.no_data);
|
||||
mDataAsString.setText(R.string.no_data);
|
||||
}
|
||||
mGattServicesList.setAdapter(gattServiceAdapter);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private void generateExportString(final List<BluetoothGattService> gattServices){
|
||||
final String unknownServiceString = getResources().getString(R.string.unknown_service);
|
||||
final String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
|
||||
final StringBuilder exportBuilder = new StringBuilder();
|
||||
private void generateExportString(final List<BluetoothGattService> gattServices) {
|
||||
final String unknownServiceString = getResources().getString(R.string.unknown_service);
|
||||
final String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
|
||||
final StringBuilder exportBuilder = new StringBuilder();
|
||||
|
||||
exportBuilder.append("Device Name: ");
|
||||
exportBuilder.append(mDeviceName);
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append("Device Address: ");
|
||||
exportBuilder.append(mDeviceAddress);
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append("Device Name: ");
|
||||
exportBuilder.append(mDeviceName);
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append("Device Address: ");
|
||||
exportBuilder.append(mDeviceAddress);
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append('\n');
|
||||
|
||||
exportBuilder.append("Services:");
|
||||
exportBuilder.append("--------------------------");
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append("Services:");
|
||||
exportBuilder.append("--------------------------");
|
||||
exportBuilder.append('\n');
|
||||
|
||||
String uuid = null;
|
||||
for (final BluetoothGattService gattService : gattServices) {
|
||||
uuid = gattService.getUuid().toString();
|
||||
String uuid = null;
|
||||
for (final BluetoothGattService gattService : gattServices) {
|
||||
uuid = gattService.getUuid().toString();
|
||||
|
||||
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownServiceString));
|
||||
exportBuilder.append(" (");
|
||||
exportBuilder.append(uuid);
|
||||
exportBuilder.append(')');
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownServiceString));
|
||||
exportBuilder.append(" (");
|
||||
exportBuilder.append(uuid);
|
||||
exportBuilder.append(')');
|
||||
exportBuilder.append('\n');
|
||||
|
||||
final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
|
||||
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
|
||||
uuid = gattCharacteristic.getUuid().toString();
|
||||
final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
|
||||
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
|
||||
uuid = gattCharacteristic.getUuid().toString();
|
||||
|
||||
exportBuilder.append('\t');
|
||||
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownCharaString));
|
||||
exportBuilder.append(" (");
|
||||
exportBuilder.append(uuid);
|
||||
exportBuilder.append(')');
|
||||
exportBuilder.append('\n');
|
||||
}
|
||||
exportBuilder.append('\t');
|
||||
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownCharaString));
|
||||
exportBuilder.append(" (");
|
||||
exportBuilder.append(uuid);
|
||||
exportBuilder.append(')');
|
||||
exportBuilder.append('\n');
|
||||
}
|
||||
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append('\n');
|
||||
}
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append('\n');
|
||||
}
|
||||
|
||||
exportBuilder.append("--------------------------");
|
||||
exportBuilder.append('\n');
|
||||
exportBuilder.append("--------------------------");
|
||||
exportBuilder.append('\n');
|
||||
|
||||
mExportString = exportBuilder.toString();
|
||||
}
|
||||
mExportString = exportBuilder.toString();
|
||||
}
|
||||
|
||||
// Demonstrates how to iterate through the supported GATT Services/Characteristics.
|
||||
// In this sample, we populate the data structure that is bound to the ExpandableListView
|
||||
// on the UI.
|
||||
private void displayGattServices(final List<BluetoothGattService> gattServices) {
|
||||
if (gattServices == null) return;
|
||||
generateExportString(gattServices);
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_gatt_services);
|
||||
|
||||
String uuid = null;
|
||||
final String unknownServiceString = getResources().getString(R.string.unknown_service);
|
||||
final String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
|
||||
final List<Map<String, String>> gattServiceData = new ArrayList<Map<String, String>>();
|
||||
final List<List<Map<String, String>>> gattCharacteristicData = new ArrayList<List<Map<String, String>>>();
|
||||
mGattCharacteristics = new ArrayList<List<BluetoothGattCharacteristic>>();
|
||||
final Intent intent = getIntent();
|
||||
final BluetoothLeDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
|
||||
mDeviceName = device.getName();
|
||||
mDeviceAddress = device.getAddress();
|
||||
|
||||
// Loops through available GATT Services.
|
||||
for (final BluetoothGattService gattService : gattServices) {
|
||||
final Map<String, String> currentServiceData = new HashMap<String, String>();
|
||||
uuid = gattService.getUuid().toString();
|
||||
currentServiceData.put(LIST_NAME, GattAttributeResolver.getAttributeName(uuid, unknownServiceString));
|
||||
currentServiceData.put(LIST_UUID, uuid);
|
||||
gattServiceData.add(currentServiceData);
|
||||
ButterKnife.inject(this);
|
||||
|
||||
final List<Map<String, String>> gattCharacteristicGroupData = new ArrayList<Map<String, String>>();
|
||||
final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
|
||||
final List<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();
|
||||
// Sets up UI references.
|
||||
((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress);
|
||||
mGattServicesList.setOnChildClickListener(servicesListClickListner);
|
||||
|
||||
// Loops through available Characteristics.
|
||||
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
|
||||
charas.add(gattCharacteristic);
|
||||
final Map<String, String> currentCharaData = new HashMap<String, String>();
|
||||
uuid = gattCharacteristic.getUuid().toString();
|
||||
currentCharaData.put(LIST_NAME, GattAttributeResolver.getAttributeName(uuid, unknownCharaString));
|
||||
currentCharaData.put(LIST_UUID, uuid);
|
||||
gattCharacteristicGroupData.add(currentCharaData);
|
||||
}
|
||||
getActionBar().setTitle(mDeviceName);
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mGattCharacteristics.add(charas);
|
||||
gattCharacteristicData.add(gattCharacteristicGroupData);
|
||||
}
|
||||
final Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
|
||||
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
final SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(
|
||||
this,
|
||||
gattServiceData,
|
||||
android.R.layout.simple_expandable_list_item_2,
|
||||
new String[] {LIST_NAME, LIST_UUID},
|
||||
new int[] { android.R.id.text1, android.R.id.text2 },
|
||||
gattCharacteristicData,
|
||||
android.R.layout.simple_expandable_list_item_2,
|
||||
new String[] {LIST_NAME, LIST_UUID},
|
||||
new int[] { android.R.id.text1, android.R.id.text2 }
|
||||
);
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.gatt_services, menu);
|
||||
if (mConnected) {
|
||||
menu.findItem(R.id.menu_connect).setVisible(false);
|
||||
menu.findItem(R.id.menu_disconnect).setVisible(true);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_connect).setVisible(true);
|
||||
menu.findItem(R.id.menu_disconnect).setVisible(false);
|
||||
}
|
||||
|
||||
mGattServicesList.setAdapter(gattServiceAdapter);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
if (mExportString == null) {
|
||||
menu.findItem(R.id.menu_share).setVisible(false);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_share).setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_gatt_services);
|
||||
return true;
|
||||
}
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final BluetoothLeDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
|
||||
mDeviceName = device.getName();
|
||||
mDeviceAddress = device.getAddress();
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbindService(mServiceConnection);
|
||||
mBluetoothLeService = null;
|
||||
}
|
||||
|
||||
ButterKnife.inject(this);
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_connect:
|
||||
mBluetoothLeService.connect(mDeviceAddress);
|
||||
return true;
|
||||
case R.id.menu_disconnect:
|
||||
mBluetoothLeService.disconnect();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.menu_share:
|
||||
final Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
final String subject = getString(R.string.exporter_email_device_services_subject, mDeviceName, mDeviceAddress);
|
||||
|
||||
// Sets up UI references.
|
||||
((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress);
|
||||
mGattServicesList.setOnChildClickListener(servicesListClickListner);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
|
||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, mExportString);
|
||||
|
||||
getActionBar().setTitle(mDeviceName);
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
startActivity(Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.exporter_email_device_list_picker_text)));
|
||||
|
||||
final Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
|
||||
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.gatt_services, menu);
|
||||
if (mConnected) {
|
||||
menu.findItem(R.id.menu_connect).setVisible(false);
|
||||
menu.findItem(R.id.menu_disconnect).setVisible(true);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_connect).setVisible(true);
|
||||
menu.findItem(R.id.menu_disconnect).setVisible(false);
|
||||
}
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver(mGattUpdateReceiver);
|
||||
}
|
||||
|
||||
if(mExportString == null){
|
||||
menu.findItem(R.id.menu_share).setVisible(false);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_share).setVisible(true);
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
|
||||
if (mBluetoothLeService != null) {
|
||||
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
|
||||
Log.d(TAG, "Connect request result=" + result);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private void updateConnectionState(final int resourceId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final int colourId;
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbindService(mServiceConnection);
|
||||
mBluetoothLeService = null;
|
||||
}
|
||||
switch (resourceId) {
|
||||
case R.string.connected:
|
||||
colourId = android.R.color.holo_green_dark;
|
||||
break;
|
||||
case R.string.disconnected:
|
||||
colourId = android.R.color.holo_red_dark;
|
||||
break;
|
||||
default:
|
||||
colourId = android.R.color.black;
|
||||
break;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case R.id.menu_connect:
|
||||
mBluetoothLeService.connect(mDeviceAddress);
|
||||
return true;
|
||||
case R.id.menu_disconnect:
|
||||
mBluetoothLeService.disconnect();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.menu_share:
|
||||
final Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
final String subject = getString(R.string.exporter_email_device_services_subject, mDeviceName, mDeviceAddress);
|
||||
mConnectionState.setText(resourceId);
|
||||
mConnectionState.setTextColor(getResources().getColor(colourId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
|
||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, mExportString);
|
||||
private static IntentFilter makeGattUpdateIntentFilter() {
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
|
||||
return intentFilter;
|
||||
}
|
||||
|
||||
startActivity(Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.exporter_email_device_list_picker_text)));
|
||||
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver(mGattUpdateReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
|
||||
if (mBluetoothLeService != null) {
|
||||
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
|
||||
Log.d(TAG, "Connect request result=" + result);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConnectionState(final int resourceId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final int colourId;
|
||||
|
||||
switch(resourceId){
|
||||
case R.string.connected:
|
||||
colourId = android.R.color.holo_green_dark;
|
||||
break;
|
||||
case R.string.disconnected:
|
||||
colourId = android.R.color.holo_red_dark;
|
||||
break;
|
||||
default:
|
||||
colourId = android.R.color.black;
|
||||
break;
|
||||
}
|
||||
|
||||
mConnectionState.setText(resourceId);
|
||||
mConnectionState.setTextColor(getResources().getColor(colourId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static IntentFilter makeGattUpdateIntentFilter() {
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
|
||||
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
|
||||
return intentFilter;
|
||||
}
|
||||
|
||||
private static String tryString(final String string, final String fallback){
|
||||
if(string == null){
|
||||
return fallback;
|
||||
} else{
|
||||
return string;
|
||||
}
|
||||
}
|
||||
private static String tryString(final String string, final String fallback) {
|
||||
if (string == null) {
|
||||
return fallback;
|
||||
} else {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
}
|
||||
+150
-149
@@ -1,8 +1,19 @@
|
||||
package uk.co.alt236.btlescan.activities;
|
||||
|
||||
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 com.commonsware.cwac.merge.MergeAdapter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
|
||||
import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData;
|
||||
@@ -12,195 +23,185 @@ 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.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 com.commonsware.cwac.merge.MergeAdapter;
|
||||
public class DeviceDetailsActivity extends ListActivity {
|
||||
public static final String EXTRA_DEVICE = "extra_device";
|
||||
|
||||
public class DeviceDetailsActivity extends ListActivity{
|
||||
public static final String EXTRA_DEVICE = "extra_device";
|
||||
private BluetoothLeDevice mDevice;
|
||||
|
||||
private BluetoothLeDevice mDevice;
|
||||
private void appendAdRecordView(final MergeAdapter adapter, final String title, final 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);
|
||||
|
||||
private void appendAdRecordView(final MergeAdapter adapter, final String title, final 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()) + "'");
|
||||
|
||||
tvTitle.setText(title );
|
||||
tvString.setText("'" + AdRecordUtils.getRecordDataAsString(record) + "'");
|
||||
tvArray.setText("'" + ByteUtils.byteArrayToHexString(record.getData()) + "'");
|
||||
adapter.addView(lt);
|
||||
}
|
||||
|
||||
adapter.addView(lt);
|
||||
}
|
||||
private void appendDeviceInfo(final MergeAdapter adapter, final 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);
|
||||
|
||||
private void appendDeviceInfo(final MergeAdapter adapter, final 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());
|
||||
|
||||
tvName.setText(device.getName());
|
||||
tvAddress.setText(device.getAddress());
|
||||
tvClass.setText(device.getBluetoothDeviceClassName());
|
||||
tvBondingState.setText(device.getBluetoothDeviceBondState());
|
||||
adapter.addView(lt);
|
||||
}
|
||||
|
||||
adapter.addView(lt);
|
||||
}
|
||||
private void appendHeader(final MergeAdapter adapter, final 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);
|
||||
|
||||
private void appendHeader(final MergeAdapter adapter, final 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);
|
||||
}
|
||||
|
||||
adapter.addView(lt);
|
||||
}
|
||||
private void appendIBeaconInfo(final MergeAdapter adapter, final 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);
|
||||
|
||||
private void appendIBeaconInfo(final MergeAdapter adapter, final 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());
|
||||
tvMajor.setText(iBeaconData.getMajor() + " (" + hexEncode(iBeaconData.getMajor()) + ")");
|
||||
tvMinor.setText(iBeaconData.getMinor() + " (" + hexEncode(iBeaconData.getMinor()) + ")");
|
||||
tvTxPower.setText(iBeaconData.getCalibratedTxPower() + " (" + hexEncode(iBeaconData.getCalibratedTxPower()) + ")");
|
||||
|
||||
tvCompanyId.setText(
|
||||
CompanyIdentifierResolver.getCompanyName(iBeaconData.getCompanyIdentifier(), getString(R.string.unknown))
|
||||
+ " (" + hexEncode(iBeaconData.getCompanyIdentifier()) + ")");
|
||||
tvAdvert.setText(iBeaconData.getIBeaconAdvertisement() + " (" + hexEncode( iBeaconData.getIBeaconAdvertisement() ) + ")");
|
||||
tvUUID.setText(iBeaconData.getUUID());
|
||||
tvMajor.setText(iBeaconData.getMajor() + " (" + hexEncode( iBeaconData.getMajor() ) + ")");
|
||||
tvMinor.setText(iBeaconData.getMinor() + " (" + hexEncode( iBeaconData.getMinor() ) + ")");
|
||||
tvTxPower.setText(iBeaconData.getCalibratedTxPower() + " (" + hexEncode( iBeaconData.getCalibratedTxPower() ) + ")");
|
||||
adapter.addView(lt);
|
||||
}
|
||||
|
||||
adapter.addView(lt);
|
||||
}
|
||||
private void appendRssiInfo(final MergeAdapter adapter, final 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);
|
||||
|
||||
private void appendRssiInfo(final MergeAdapter adapter, final 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()));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
adapter.addView(lt);
|
||||
}
|
||||
private void appendSimpleText(final MergeAdapter adapter, final byte[] data) {
|
||||
appendSimpleText(adapter, ByteUtils.byteArrayToHexString(data));
|
||||
}
|
||||
|
||||
private void appendSimpleText(final MergeAdapter adapter, final byte[] data){
|
||||
appendSimpleText(adapter, ByteUtils.byteArrayToHexString(data));
|
||||
}
|
||||
private void appendSimpleText(final MergeAdapter adapter, final String data) {
|
||||
final LinearLayout lt = (LinearLayout) getLayoutInflater().inflate(R.layout.list_item_view_textview, null);
|
||||
final TextView tvData = (TextView) lt.findViewById(R.id.data);
|
||||
|
||||
private void appendSimpleText(final MergeAdapter adapter, final 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);
|
||||
|
||||
tvData.setText(data);
|
||||
|
||||
adapter.addView(lt);
|
||||
}
|
||||
adapter.addView(lt);
|
||||
}
|
||||
|
||||
|
||||
private String formatRssi(final double rssi){
|
||||
return getString(R.string.formatter_db, String.valueOf(rssi));
|
||||
}
|
||||
private String formatRssi(final double rssi) {
|
||||
return getString(R.string.formatter_db, String.valueOf(rssi));
|
||||
}
|
||||
|
||||
private String formatRssi(final int rssi){
|
||||
return getString(R.string.formatter_db, String.valueOf(rssi));
|
||||
}
|
||||
private String formatRssi(final int rssi) {
|
||||
return getString(R.string.formatter_db, String.valueOf(rssi));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_details);
|
||||
ButterKnife.inject(this);
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_details);
|
||||
ButterKnife.inject(this);
|
||||
|
||||
mDevice = getIntent().getParcelableExtra(EXTRA_DEVICE);
|
||||
mDevice = getIntent().getParcelableExtra(EXTRA_DEVICE);
|
||||
|
||||
pupulateDetails(mDevice);
|
||||
}
|
||||
pupulateDetails(mDevice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.details, menu);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.details, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_connect:
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_connect:
|
||||
|
||||
final Intent intent = new Intent(this, DeviceControlActivity.class);
|
||||
intent.putExtra(DeviceControlActivity.EXTRA_DEVICE, mDevice);
|
||||
final Intent intent = new Intent(this, DeviceControlActivity.class);
|
||||
intent.putExtra(DeviceControlActivity.EXTRA_DEVICE, mDevice);
|
||||
|
||||
startActivity(intent);
|
||||
startActivity(intent);
|
||||
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void pupulateDetails(final BluetoothLeDevice device) {
|
||||
final MergeAdapter adapter = new MergeAdapter();
|
||||
private void pupulateDetails(final BluetoothLeDevice device) {
|
||||
final MergeAdapter adapter = new MergeAdapter();
|
||||
|
||||
if(device == null){
|
||||
appendHeader(adapter, getString(R.string.header_device_info));
|
||||
appendSimpleText(adapter, getString(R.string.invalid_device_data));
|
||||
} else {
|
||||
appendHeader(adapter, getString(R.string.header_device_info));
|
||||
appendDeviceInfo(adapter, device);
|
||||
if (device == null) {
|
||||
appendHeader(adapter, getString(R.string.header_device_info));
|
||||
appendSimpleText(adapter, getString(R.string.invalid_device_data));
|
||||
} else {
|
||||
appendHeader(adapter, getString(R.string.header_device_info));
|
||||
appendDeviceInfo(adapter, device);
|
||||
|
||||
appendHeader(adapter, getString(R.string.header_rssi_info));
|
||||
appendRssiInfo(adapter, device);
|
||||
appendHeader(adapter, getString(R.string.header_rssi_info));
|
||||
appendRssiInfo(adapter, device);
|
||||
|
||||
appendHeader(adapter, getString(R.string.header_scan_record));
|
||||
appendSimpleText(adapter, device.getScanRecord());
|
||||
appendHeader(adapter, getString(R.string.header_scan_record));
|
||||
appendSimpleText(adapter, device.getScanRecord());
|
||||
|
||||
final Collection<AdRecord> adRecords = device.getAdRecordStore().getRecordsAsCollection();
|
||||
if(adRecords.size() > 0){
|
||||
appendHeader(adapter, getString(R.string.header_raw_ad_records));
|
||||
final Collection<AdRecord> adRecords = device.getAdRecordStore().getRecordsAsCollection();
|
||||
if (adRecords.size() > 0) {
|
||||
appendHeader(adapter, getString(R.string.header_raw_ad_records));
|
||||
|
||||
for(final AdRecord record : adRecords){
|
||||
for (final AdRecord record : adRecords) {
|
||||
|
||||
appendAdRecordView(
|
||||
adapter,
|
||||
"#" + record.getType() + " " + record.getHumanReadableType(),
|
||||
record);
|
||||
}
|
||||
}
|
||||
appendAdRecordView(
|
||||
adapter,
|
||||
"#" + record.getType() + " " + record.getHumanReadableType(),
|
||||
record);
|
||||
}
|
||||
}
|
||||
|
||||
final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
|
||||
if(isIBeacon){
|
||||
final IBeaconManufacturerData iBeaconData = new IBeaconManufacturerData(device);
|
||||
appendHeader(adapter, getString(R.string.header_ibeacon_data));
|
||||
appendIBeaconInfo(adapter, iBeaconData);
|
||||
}
|
||||
final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
|
||||
if (isIBeacon) {
|
||||
final IBeaconManufacturerData iBeaconData = new IBeaconManufacturerData(device);
|
||||
appendHeader(adapter, getString(R.string.header_ibeacon_data));
|
||||
appendIBeaconInfo(adapter, iBeaconData);
|
||||
}
|
||||
|
||||
}
|
||||
getListView().setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
getListView().setAdapter(adapter);
|
||||
}
|
||||
|
||||
private static String formatTime(final long time){
|
||||
return TimeFormatter.getIsoDateTime(time);
|
||||
}
|
||||
private static String formatTime(final long time) {
|
||||
return TimeFormatter.getIsoDateTime(time);
|
||||
}
|
||||
|
||||
private static String hexEncode(final int integer){
|
||||
return "0x" + Integer.toHexString(integer).toUpperCase(Locale.US);
|
||||
}
|
||||
private static String hexEncode(final int integer) {
|
||||
return "0x" + Integer.toHexString(integer).toUpperCase(Locale.US);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
package uk.co.alt236.btlescan.activities;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.btlescan.R;
|
||||
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.BluetoothUtils;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ListActivity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
@@ -22,174 +15,186 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.btlescan.R;
|
||||
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.BluetoothUtils;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
|
||||
public class MainActivity extends ListActivity {
|
||||
@InjectView(R.id.tvBluetoothLe) TextView mTvBluetoothLeStatus;
|
||||
@InjectView(R.id.tvBluetoothStatus) TextView mTvBluetoothStatus;
|
||||
@InjectView(R.id.tvItemCount) TextView mTvItemCount;
|
||||
@InjectView(R.id.tvBluetoothLe)
|
||||
TextView mTvBluetoothLeStatus;
|
||||
@InjectView(R.id.tvBluetoothStatus)
|
||||
TextView mTvBluetoothStatus;
|
||||
@InjectView(R.id.tvItemCount)
|
||||
TextView mTvItemCount;
|
||||
|
||||
private BluetoothUtils mBluetoothUtils;
|
||||
private BluetoothLeScanner mScanner;
|
||||
private LeDeviceListAdapter mLeDeviceListAdapter;
|
||||
private BluetoothLeDeviceStore mDeviceStore;
|
||||
private BluetoothUtils mBluetoothUtils;
|
||||
private BluetoothLeScanner mScanner;
|
||||
private LeDeviceListAdapter mLeDeviceListAdapter;
|
||||
private BluetoothLeDeviceStore mDeviceStore;
|
||||
|
||||
private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
|
||||
@Override
|
||||
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
|
||||
private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
|
||||
@Override
|
||||
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
|
||||
|
||||
final BluetoothLeDevice deviceLe = new BluetoothLeDevice(device, rssi, scanRecord, System.currentTimeMillis());
|
||||
mDeviceStore.addDevice(deviceLe);
|
||||
final EasyObjectCursor<BluetoothLeDevice> c = mDeviceStore.getDeviceCursor();
|
||||
final BluetoothLeDevice deviceLe = new BluetoothLeDevice(device, rssi, scanRecord, System.currentTimeMillis());
|
||||
mDeviceStore.addDevice(deviceLe);
|
||||
final EasyObjectCursor<BluetoothLeDevice> c = mDeviceStore.getDeviceCursor();
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mLeDeviceListAdapter.swapCursor(c);
|
||||
updateItemCount(mLeDeviceListAdapter.getCount());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mLeDeviceListAdapter.swapCursor(c);
|
||||
updateItemCount(mLeDeviceListAdapter.getCount());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private void updateItemCount(final int count){
|
||||
mTvItemCount.setText(
|
||||
getString(
|
||||
R.string.formatter_item_count,
|
||||
String.valueOf(count)));
|
||||
}
|
||||
private void displayAboutDialog() {
|
||||
// REALLY REALLY LAZY LINKIFIED DIALOG
|
||||
final int paddingSizeDp = 5;
|
||||
final float scale = getResources().getDisplayMetrics().density;
|
||||
final int dpAsPixels = (int) (paddingSizeDp * scale + 0.5f);
|
||||
|
||||
private void displayAboutDialog(){
|
||||
// REALLY REALLY LAZY LINKIFIED DIALOG
|
||||
final int paddingSizeDp = 5;
|
||||
final float scale = getResources().getDisplayMetrics().density;
|
||||
final int dpAsPixels = (int) (paddingSizeDp * scale + 0.5f);
|
||||
final TextView textView = new TextView(this);
|
||||
final SpannableString text = new SpannableString(getString(R.string.about_dialog_text));
|
||||
|
||||
final TextView textView=new TextView(this);
|
||||
final SpannableString text = new SpannableString(getString(R.string.about_dialog_text));
|
||||
textView.setText(text);
|
||||
textView.setAutoLinkMask(RESULT_OK);
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
textView.setPadding(dpAsPixels, dpAsPixels, dpAsPixels, dpAsPixels);
|
||||
|
||||
textView.setText(text);
|
||||
textView.setAutoLinkMask(RESULT_OK);
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
textView.setPadding(dpAsPixels, dpAsPixels, dpAsPixels, dpAsPixels);
|
||||
Linkify.addLinks(text, Linkify.ALL);
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.menu_about)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(final DialogInterface dialog, final int id) {
|
||||
}
|
||||
})
|
||||
.setView(textView)
|
||||
.show();
|
||||
}
|
||||
|
||||
Linkify.addLinks(text, Linkify.ALL);
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.menu_about)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(final DialogInterface dialog, final int id) {}
|
||||
})
|
||||
.setView(textView)
|
||||
.show();
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
ButterKnife.inject(this);
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
ButterKnife.inject(this);
|
||||
mDeviceStore = new BluetoothLeDeviceStore();
|
||||
mBluetoothUtils = new BluetoothUtils(this);
|
||||
mScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils);
|
||||
updateItemCount(0);
|
||||
}
|
||||
|
||||
mDeviceStore = new BluetoothLeDeviceStore();
|
||||
mBluetoothUtils = new BluetoothUtils(this);
|
||||
mScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils);
|
||||
updateItemCount(0);
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main, menu);
|
||||
if (!mScanner.isScanning()) {
|
||||
menu.findItem(R.id.menu_stop).setVisible(false);
|
||||
menu.findItem(R.id.menu_scan).setVisible(true);
|
||||
menu.findItem(R.id.menu_refresh).setActionView(null);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_stop).setVisible(true);
|
||||
menu.findItem(R.id.menu_scan).setVisible(false);
|
||||
menu.findItem(R.id.menu_refresh).setActionView(R.layout.actionbar_progress_indeterminate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main, menu);
|
||||
if (!mScanner.isScanning()) {
|
||||
menu.findItem(R.id.menu_stop).setVisible(false);
|
||||
menu.findItem(R.id.menu_scan).setVisible(true);
|
||||
menu.findItem(R.id.menu_refresh).setActionView(null);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_stop).setVisible(true);
|
||||
menu.findItem(R.id.menu_scan).setVisible(false);
|
||||
menu.findItem(R.id.menu_refresh).setActionView(R.layout.actionbar_progress_indeterminate);
|
||||
}
|
||||
if (getListView().getCount() > 0) {
|
||||
menu.findItem(R.id.menu_share).setVisible(true);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_share).setVisible(false);
|
||||
}
|
||||
|
||||
if(getListView().getCount() > 0){
|
||||
menu.findItem(R.id.menu_share).setVisible(true);
|
||||
} else {
|
||||
menu.findItem(R.id.menu_share).setVisible(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
protected void onListItemClick(final ListView l, final View v, final int position, final long id) {
|
||||
final BluetoothLeDevice device = mLeDeviceListAdapter.getItem(position);
|
||||
if (device == null) return;
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(final ListView l, final View v, final int position, final long id) {
|
||||
final BluetoothLeDevice device = mLeDeviceListAdapter.getItem(position);
|
||||
if (device == null) return;
|
||||
final Intent intent = new Intent(this, DeviceDetailsActivity.class);
|
||||
intent.putExtra(DeviceDetailsActivity.EXTRA_DEVICE, device);
|
||||
|
||||
final Intent intent = new Intent(this, DeviceDetailsActivity.class);
|
||||
intent.putExtra(DeviceDetailsActivity.EXTRA_DEVICE, device);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_scan:
|
||||
startScan();
|
||||
break;
|
||||
case R.id.menu_stop:
|
||||
mScanner.scanLeDevice(-1, false);
|
||||
invalidateOptionsMenu();
|
||||
break;
|
||||
case R.id.menu_about:
|
||||
displayAboutDialog();
|
||||
break;
|
||||
case R.id.menu_share:
|
||||
mDeviceStore.shareDataAsEmail(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_scan:
|
||||
startScan();
|
||||
break;
|
||||
case R.id.menu_stop:
|
||||
mScanner.scanLeDevice(-1, false);
|
||||
invalidateOptionsMenu();
|
||||
break;
|
||||
case R.id.menu_about:
|
||||
displayAboutDialog();
|
||||
break;
|
||||
case R.id.menu_share:
|
||||
mDeviceStore.shareDataAsEmail(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
mScanner.scanLeDevice(-1, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
mScanner.scanLeDevice(-1, false);
|
||||
}
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn();
|
||||
final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
|
||||
|
||||
@Override
|
||||
public void onResume(){
|
||||
super.onResume();
|
||||
final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn();
|
||||
final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
|
||||
if (mIsBluetoothOn) {
|
||||
mTvBluetoothStatus.setText(R.string.on);
|
||||
} else {
|
||||
mTvBluetoothStatus.setText(R.string.off);
|
||||
}
|
||||
|
||||
if(mIsBluetoothOn){
|
||||
mTvBluetoothStatus.setText(R.string.on);
|
||||
} else {
|
||||
mTvBluetoothStatus.setText(R.string.off);
|
||||
}
|
||||
if (mIsBluetoothLePresent) {
|
||||
mTvBluetoothLeStatus.setText(R.string.supported);
|
||||
} else {
|
||||
mTvBluetoothLeStatus.setText(R.string.not_supported);
|
||||
}
|
||||
|
||||
if(mIsBluetoothLePresent){
|
||||
mTvBluetoothLeStatus.setText(R.string.supported);
|
||||
} else {
|
||||
mTvBluetoothLeStatus.setText(R.string.not_supported);
|
||||
}
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
private void startScan() {
|
||||
final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn();
|
||||
final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
|
||||
mDeviceStore.clear();
|
||||
updateItemCount(0);
|
||||
|
||||
private void startScan(){
|
||||
final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn();
|
||||
final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
|
||||
mDeviceStore.clear();
|
||||
updateItemCount(0);
|
||||
mLeDeviceListAdapter = new LeDeviceListAdapter(this, mDeviceStore.getDeviceCursor());
|
||||
setListAdapter(mLeDeviceListAdapter);
|
||||
|
||||
mLeDeviceListAdapter = new LeDeviceListAdapter(this, mDeviceStore.getDeviceCursor());
|
||||
setListAdapter(mLeDeviceListAdapter);
|
||||
mBluetoothUtils.askUserToEnableBluetoothIfNeeded();
|
||||
if (mIsBluetoothOn && mIsBluetoothLePresent) {
|
||||
mScanner.scanLeDevice(-1, true);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
mBluetoothUtils.askUserToEnableBluetoothIfNeeded();
|
||||
if(mIsBluetoothOn && mIsBluetoothLePresent){
|
||||
mScanner.scanLeDevice(-1, true);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
private void updateItemCount(final int count) {
|
||||
mTvItemCount.setText(
|
||||
getString(
|
||||
R.string.formatter_item_count,
|
||||
String.valueOf(count)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package uk.co.alt236.btlescan.adapters;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.IBeaconDevice;
|
||||
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
|
||||
import uk.co.alt236.btlescan.R;
|
||||
import uk.co.alt236.btlescan.util.Constants;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
import android.app.Activity;
|
||||
import android.support.v4.widget.SimpleCursorAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -13,111 +7,119 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.IBeaconDevice;
|
||||
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
|
||||
import uk.co.alt236.btlescan.R;
|
||||
import uk.co.alt236.btlescan.util.Constants;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
|
||||
// Adapter for holding devices found through scanning.
|
||||
public class LeDeviceListAdapter extends SimpleCursorAdapter {
|
||||
private final LayoutInflater mInflator;
|
||||
private final Activity mActivity;
|
||||
private final LayoutInflater mInflator;
|
||||
private final Activity mActivity;
|
||||
|
||||
public LeDeviceListAdapter(final Activity activity, final EasyObjectCursor<BluetoothLeDevice> cursor) {
|
||||
super(activity, R.layout.list_item_device, cursor, new String[0], new int[0], 0);
|
||||
mInflator = activity.getLayoutInflater();
|
||||
mActivity = activity;
|
||||
}
|
||||
public LeDeviceListAdapter(final Activity activity, final EasyObjectCursor<BluetoothLeDevice> cursor) {
|
||||
super(activity, R.layout.list_item_device, cursor, new String[0], new int[0], 0);
|
||||
mInflator = activity.getLayoutInflater();
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public EasyObjectCursor<BluetoothLeDevice> getCursor(){
|
||||
return ((EasyObjectCursor<BluetoothLeDevice>) super.getCursor());
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public EasyObjectCursor<BluetoothLeDevice> getCursor() {
|
||||
return ((EasyObjectCursor<BluetoothLeDevice>) super.getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothLeDevice getItem(final int i){
|
||||
return getCursor().getItem(i);
|
||||
}
|
||||
@Override
|
||||
public BluetoothLeDevice getItem(final int i) {
|
||||
return getCursor().getItem(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int i) {
|
||||
return i;
|
||||
}
|
||||
@Override
|
||||
public long getItemId(final int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int i, View view, final ViewGroup viewGroup) {
|
||||
final ViewHolder viewHolder;
|
||||
// General ListView optimization code.
|
||||
if (view == null) {
|
||||
view = mInflator.inflate(R.layout.list_item_device, null);
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
|
||||
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
|
||||
viewHolder.deviceRssi = (TextView) view.findViewById(R.id.device_rssi);
|
||||
viewHolder.deviceIcon = (ImageView) view.findViewById(R.id.device_icon);
|
||||
viewHolder.deviceLastUpdated = (TextView) view.findViewById(R.id.device_last_update);
|
||||
viewHolder.ibeaconMajor = (TextView) view.findViewById(R.id.ibeacon_major);
|
||||
viewHolder.ibeaconMinor = (TextView) view.findViewById(R.id.ibeacon_minor);
|
||||
viewHolder.ibeaconDistance = (TextView) view.findViewById(R.id.ibeacon_distance);
|
||||
viewHolder.ibeaconUUID = (TextView) view.findViewById(R.id.ibeacon_uuid);
|
||||
viewHolder.ibeaconTxPower = (TextView) view.findViewById(R.id.ibeacon_tx_power);
|
||||
viewHolder.ibeaconSection = view.findViewById(R.id.ibeacon_section);
|
||||
viewHolder.ibeaconDistanceDescriptor = (TextView) view.findViewById(R.id.ibeacon_distance_descriptor);
|
||||
view.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) view.getTag();
|
||||
}
|
||||
@Override
|
||||
public View getView(final int i, View view, final ViewGroup viewGroup) {
|
||||
final ViewHolder viewHolder;
|
||||
// General ListView optimization code.
|
||||
if (view == null) {
|
||||
view = mInflator.inflate(R.layout.list_item_device, null);
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
|
||||
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
|
||||
viewHolder.deviceRssi = (TextView) view.findViewById(R.id.device_rssi);
|
||||
viewHolder.deviceIcon = (ImageView) view.findViewById(R.id.device_icon);
|
||||
viewHolder.deviceLastUpdated = (TextView) view.findViewById(R.id.device_last_update);
|
||||
viewHolder.ibeaconMajor = (TextView) view.findViewById(R.id.ibeacon_major);
|
||||
viewHolder.ibeaconMinor = (TextView) view.findViewById(R.id.ibeacon_minor);
|
||||
viewHolder.ibeaconDistance = (TextView) view.findViewById(R.id.ibeacon_distance);
|
||||
viewHolder.ibeaconUUID = (TextView) view.findViewById(R.id.ibeacon_uuid);
|
||||
viewHolder.ibeaconTxPower = (TextView) view.findViewById(R.id.ibeacon_tx_power);
|
||||
viewHolder.ibeaconSection = view.findViewById(R.id.ibeacon_section);
|
||||
viewHolder.ibeaconDistanceDescriptor = (TextView) view.findViewById(R.id.ibeacon_distance_descriptor);
|
||||
view.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) view.getTag();
|
||||
}
|
||||
|
||||
final BluetoothLeDevice device = getCursor().getItem(i);
|
||||
final String deviceName = device.getName();
|
||||
final double rssi = device.getRssi();
|
||||
final BluetoothLeDevice device = getCursor().getItem(i);
|
||||
final String deviceName = device.getName();
|
||||
final double rssi = device.getRssi();
|
||||
|
||||
if (deviceName != null && deviceName.length() > 0){
|
||||
viewHolder.deviceName.setText(deviceName);
|
||||
} else{
|
||||
viewHolder.deviceName.setText(R.string.unknown_device);
|
||||
}
|
||||
if (deviceName != null && deviceName.length() > 0) {
|
||||
viewHolder.deviceName.setText(deviceName);
|
||||
} else {
|
||||
viewHolder.deviceName.setText(R.string.unknown_device);
|
||||
}
|
||||
|
||||
if (IBeaconUtils.isThisAnIBeacon(device)){
|
||||
final IBeaconDevice iBeacon = new IBeaconDevice(device);
|
||||
final String accuracy = Constants.DOUBLE_TWO_DIGIT_ACCURACY.format(iBeacon.getAccuracy());
|
||||
if (IBeaconUtils.isThisAnIBeacon(device)) {
|
||||
final IBeaconDevice iBeacon = new IBeaconDevice(device);
|
||||
final String accuracy = Constants.DOUBLE_TWO_DIGIT_ACCURACY.format(iBeacon.getAccuracy());
|
||||
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.ic_device_ibeacon);
|
||||
viewHolder.ibeaconSection.setVisibility(View.VISIBLE);
|
||||
viewHolder.ibeaconMajor.setText(String.valueOf(iBeacon.getMajor()));
|
||||
viewHolder.ibeaconMinor.setText(String.valueOf(iBeacon.getMinor()));
|
||||
viewHolder.ibeaconTxPower.setText(String.valueOf(iBeacon.getCalibratedTxPower()));
|
||||
viewHolder.ibeaconUUID.setText(iBeacon.getUUID());
|
||||
viewHolder.ibeaconDistance.setText(
|
||||
mActivity.getString(R.string.formatter_meters, accuracy));
|
||||
viewHolder.ibeaconDistanceDescriptor.setText(iBeacon.getDistanceDescriptor().toString());
|
||||
} else {
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.ic_bluetooth);
|
||||
viewHolder.ibeaconSection.setVisibility(View.GONE);
|
||||
}
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.ic_device_ibeacon);
|
||||
viewHolder.ibeaconSection.setVisibility(View.VISIBLE);
|
||||
viewHolder.ibeaconMajor.setText(String.valueOf(iBeacon.getMajor()));
|
||||
viewHolder.ibeaconMinor.setText(String.valueOf(iBeacon.getMinor()));
|
||||
viewHolder.ibeaconTxPower.setText(String.valueOf(iBeacon.getCalibratedTxPower()));
|
||||
viewHolder.ibeaconUUID.setText(iBeacon.getUUID());
|
||||
viewHolder.ibeaconDistance.setText(
|
||||
mActivity.getString(R.string.formatter_meters, accuracy));
|
||||
viewHolder.ibeaconDistanceDescriptor.setText(iBeacon.getDistanceDescriptor().toString());
|
||||
} else {
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.ic_bluetooth);
|
||||
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()));
|
||||
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(
|
||||
android.text.format.DateFormat.format(
|
||||
Constants.TIME_FORMAT, new java.util.Date(device.getTimestamp())));
|
||||
viewHolder.deviceAddress.setText(device.getAddress());
|
||||
viewHolder.deviceRssi.setText(rssiString + " / " + runningAverageRssiString);
|
||||
return view;
|
||||
}
|
||||
viewHolder.deviceLastUpdated.setText(
|
||||
android.text.format.DateFormat.format(
|
||||
Constants.TIME_FORMAT, new java.util.Date(device.getTimestamp())));
|
||||
viewHolder.deviceAddress.setText(device.getAddress());
|
||||
viewHolder.deviceRssi.setText(rssiString + " / " + runningAverageRssiString);
|
||||
return view;
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
TextView deviceName;
|
||||
TextView deviceAddress;
|
||||
TextView deviceRssi;
|
||||
TextView ibeaconUUID;
|
||||
TextView ibeaconMajor;
|
||||
TextView ibeaconMinor;
|
||||
TextView ibeaconTxPower;
|
||||
TextView ibeaconDistance;
|
||||
TextView ibeaconDistanceDescriptor;
|
||||
TextView deviceLastUpdated;
|
||||
View ibeaconSection;
|
||||
ImageView deviceIcon;
|
||||
}
|
||||
static class ViewHolder {
|
||||
TextView deviceName;
|
||||
TextView deviceAddress;
|
||||
TextView deviceRssi;
|
||||
TextView ibeaconUUID;
|
||||
TextView ibeaconMajor;
|
||||
TextView ibeaconMinor;
|
||||
TextView ibeaconTxPower;
|
||||
TextView ibeaconDistance;
|
||||
TextView ibeaconDistanceDescriptor;
|
||||
TextView deviceLastUpdated;
|
||||
View ibeaconSection;
|
||||
ImageView deviceIcon;
|
||||
}
|
||||
|
||||
}
|
||||
+123
-125
@@ -1,5 +1,9 @@
|
||||
package uk.co.alt236.btlescan.containers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
@@ -19,158 +23,133 @@ import uk.co.alt236.btlescan.R;
|
||||
import uk.co.alt236.btlescan.util.CsvWriterHelper;
|
||||
import uk.co.alt236.btlescan.util.TimeFormatter;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
public class BluetoothLeDeviceStore {
|
||||
private final Map<String, BluetoothLeDevice> mDeviceMap;
|
||||
private final Map<String, BluetoothLeDevice> mDeviceMap;
|
||||
|
||||
|
||||
public BluetoothLeDeviceStore(){
|
||||
mDeviceMap = new HashMap<String, BluetoothLeDevice>();
|
||||
}
|
||||
public BluetoothLeDeviceStore() {
|
||||
mDeviceMap = new HashMap<String, BluetoothLeDevice>();
|
||||
}
|
||||
|
||||
public void addDevice(final BluetoothLeDevice device){
|
||||
if(mDeviceMap.containsKey(device.getAddress())){
|
||||
mDeviceMap.get(device.getAddress()).updateRssiReading(device.getTimestamp(), device.getRssi());
|
||||
} else {
|
||||
mDeviceMap.put(device.getAddress(), device);
|
||||
}
|
||||
}
|
||||
public void addDevice(final BluetoothLeDevice device) {
|
||||
if (mDeviceMap.containsKey(device.getAddress())) {
|
||||
mDeviceMap.get(device.getAddress()).updateRssiReading(device.getTimestamp(), device.getRssi());
|
||||
} else {
|
||||
mDeviceMap.put(device.getAddress(), device);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
mDeviceMap.clear();
|
||||
}
|
||||
public void clear() {
|
||||
mDeviceMap.clear();
|
||||
}
|
||||
|
||||
public EasyObjectCursor<BluetoothLeDevice> getDeviceCursor() {
|
||||
return new EasyObjectCursor<BluetoothLeDevice>(
|
||||
BluetoothLeDevice.class,
|
||||
getDeviceList(),
|
||||
"address");
|
||||
}
|
||||
|
||||
private static FileWriter generateFile(final File file, final String contents){
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(file);
|
||||
writer.append(contents);
|
||||
writer.flush();
|
||||
public List<BluetoothLeDevice> getDeviceList() {
|
||||
final List<BluetoothLeDevice> methodResult = new ArrayList<BluetoothLeDevice>(mDeviceMap.values());
|
||||
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
try {
|
||||
writer.close();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
Collections.sort(methodResult, new Comparator<BluetoothLeDevice>() {
|
||||
|
||||
public EasyObjectCursor<BluetoothLeDevice> getDeviceCursor(){
|
||||
return new EasyObjectCursor<BluetoothLeDevice>(
|
||||
BluetoothLeDevice.class,
|
||||
getDeviceList(),
|
||||
"address");
|
||||
}
|
||||
@Override
|
||||
public int compare(final BluetoothLeDevice arg0, final BluetoothLeDevice arg1) {
|
||||
return arg0.getAddress().compareToIgnoreCase(arg1.getAddress());
|
||||
}
|
||||
});
|
||||
|
||||
public List<BluetoothLeDevice> getDeviceList(){
|
||||
final List<BluetoothLeDevice> methodResult = new ArrayList<BluetoothLeDevice>(mDeviceMap.values());
|
||||
return methodResult;
|
||||
}
|
||||
|
||||
Collections.sort(methodResult, new Comparator<BluetoothLeDevice>() {
|
||||
private String getListAsCsv() {
|
||||
final List<BluetoothLeDevice> list = getDeviceList();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(CsvWriterHelper.addStuff("mac"));
|
||||
sb.append(CsvWriterHelper.addStuff("name"));
|
||||
sb.append(CsvWriterHelper.addStuff("firstTimestamp"));
|
||||
sb.append(CsvWriterHelper.addStuff("firstRssi"));
|
||||
sb.append(CsvWriterHelper.addStuff("currentTimestamp"));
|
||||
sb.append(CsvWriterHelper.addStuff("currentRssi"));
|
||||
sb.append(CsvWriterHelper.addStuff("adRecord"));
|
||||
sb.append(CsvWriterHelper.addStuff("iBeacon"));
|
||||
sb.append(CsvWriterHelper.addStuff("uuid"));
|
||||
sb.append(CsvWriterHelper.addStuff("major"));
|
||||
sb.append(CsvWriterHelper.addStuff("minor"));
|
||||
sb.append(CsvWriterHelper.addStuff("txPower"));
|
||||
sb.append(CsvWriterHelper.addStuff("distance"));
|
||||
sb.append(CsvWriterHelper.addStuff("accuracy"));
|
||||
sb.append('\n');
|
||||
|
||||
@Override
|
||||
public int compare(final BluetoothLeDevice arg0, final BluetoothLeDevice arg1) {
|
||||
return arg0.getAddress().compareToIgnoreCase(arg1.getAddress());
|
||||
}
|
||||
});
|
||||
for (final BluetoothLeDevice device : list) {
|
||||
sb.append(CsvWriterHelper.addStuff(device.getAddress()));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getName()));
|
||||
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getFirstTimestamp())));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getFirstRssi()));
|
||||
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getTimestamp())));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getRssi()));
|
||||
sb.append(CsvWriterHelper.addStuff(ByteUtils.byteArrayToHexString(device.getScanRecord())));
|
||||
final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
|
||||
final String uuid;
|
||||
final String minor;
|
||||
final String major;
|
||||
final String txPower;
|
||||
final String distance;
|
||||
final String accuracy;
|
||||
|
||||
return methodResult;
|
||||
}
|
||||
if (isIBeacon) {
|
||||
final IBeaconDevice beacon = new IBeaconDevice(device);
|
||||
uuid = String.valueOf(beacon.getUUID());
|
||||
minor = String.valueOf(beacon.getMinor());
|
||||
major = String.valueOf(beacon.getMajor());
|
||||
txPower = String.valueOf(beacon.getCalibratedTxPower());
|
||||
distance = beacon.getDistanceDescriptor().toString().toLowerCase(Locale.US);
|
||||
accuracy = String.valueOf(beacon.getAccuracy());
|
||||
} else {
|
||||
uuid = "";
|
||||
minor = "";
|
||||
major = "";
|
||||
txPower = "";
|
||||
distance = "";
|
||||
accuracy = "";
|
||||
}
|
||||
|
||||
sb.append(CsvWriterHelper.addStuff(isIBeacon));
|
||||
sb.append(CsvWriterHelper.addStuff(uuid));
|
||||
sb.append(CsvWriterHelper.addStuff(minor));
|
||||
sb.append(CsvWriterHelper.addStuff(major));
|
||||
sb.append(CsvWriterHelper.addStuff(txPower));
|
||||
sb.append(CsvWriterHelper.addStuff(distance));
|
||||
sb.append(CsvWriterHelper.addStuff(accuracy));
|
||||
|
||||
private String getListAsCsv(){
|
||||
final List<BluetoothLeDevice> list = getDeviceList();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(CsvWriterHelper.addStuff("mac"));
|
||||
sb.append(CsvWriterHelper.addStuff("name"));
|
||||
sb.append(CsvWriterHelper.addStuff("firstTimestamp"));
|
||||
sb.append(CsvWriterHelper.addStuff("firstRssi"));
|
||||
sb.append(CsvWriterHelper.addStuff("currentTimestamp"));
|
||||
sb.append(CsvWriterHelper.addStuff("currentRssi"));
|
||||
sb.append(CsvWriterHelper.addStuff("adRecord"));
|
||||
sb.append(CsvWriterHelper.addStuff("iBeacon"));
|
||||
sb.append(CsvWriterHelper.addStuff("uuid"));
|
||||
sb.append(CsvWriterHelper.addStuff("major"));
|
||||
sb.append(CsvWriterHelper.addStuff("minor"));
|
||||
sb.append(CsvWriterHelper.addStuff("txPower"));
|
||||
sb.append(CsvWriterHelper.addStuff("distance"));
|
||||
sb.append(CsvWriterHelper.addStuff("accuracy"));
|
||||
sb.append('\n');
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
for(final BluetoothLeDevice device : list){
|
||||
sb.append(CsvWriterHelper.addStuff(device.getAddress()));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getName()));
|
||||
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getFirstTimestamp())));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getFirstRssi()));
|
||||
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getTimestamp())));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getRssi()));
|
||||
sb.append(CsvWriterHelper.addStuff(ByteUtils.byteArrayToHexString(device.getScanRecord())));
|
||||
final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
|
||||
final String uuid;
|
||||
final String minor;
|
||||
final String major;
|
||||
final String txPower;
|
||||
final String distance;
|
||||
final String accuracy;
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
if(isIBeacon){
|
||||
final IBeaconDevice beacon = new IBeaconDevice(device);
|
||||
uuid = String.valueOf(beacon.getUUID());
|
||||
minor = String.valueOf(beacon.getMinor());
|
||||
major = String.valueOf(beacon.getMajor());
|
||||
txPower = String.valueOf(beacon.getCalibratedTxPower());
|
||||
distance = beacon.getDistanceDescriptor().toString().toLowerCase(Locale.US);
|
||||
accuracy = String.valueOf(beacon.getAccuracy());
|
||||
} else {
|
||||
uuid = "";
|
||||
minor = "";
|
||||
major = "";
|
||||
txPower = "";
|
||||
distance = "";
|
||||
accuracy = "";
|
||||
}
|
||||
public void shareDataAsEmail(final Context context) {
|
||||
final long timeInMillis = System.currentTimeMillis();
|
||||
|
||||
sb.append(CsvWriterHelper.addStuff(isIBeacon));
|
||||
sb.append(CsvWriterHelper.addStuff(uuid));
|
||||
sb.append(CsvWriterHelper.addStuff(minor));
|
||||
sb.append(CsvWriterHelper.addStuff(major));
|
||||
sb.append(CsvWriterHelper.addStuff(txPower));
|
||||
sb.append(CsvWriterHelper.addStuff(distance));
|
||||
sb.append(CsvWriterHelper.addStuff(accuracy));
|
||||
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public void shareDataAsEmail(final Context context){
|
||||
final long timeInMillis = System.currentTimeMillis();
|
||||
|
||||
final String to = null;
|
||||
final String to = null;
|
||||
final String subject = context.getString(
|
||||
R.string.exporter_email_device_list_subject,
|
||||
TimeFormatter.getIsoDateTime(timeInMillis));
|
||||
R.string.exporter_email_device_list_subject,
|
||||
TimeFormatter.getIsoDateTime(timeInMillis));
|
||||
|
||||
final String message = context.getString(R.string.exporter_email_device_list_body);
|
||||
|
||||
final Intent i = new Intent(Intent.ACTION_SEND);
|
||||
i.setType("plain/text");
|
||||
try {
|
||||
final File outputDir = context.getCacheDir();
|
||||
final File outputFile = File.createTempFile("bluetooth_le_" + timeInMillis, ".csv", outputDir);
|
||||
outputFile.setReadable(true, false);
|
||||
final File outputDir = context.getCacheDir();
|
||||
final File outputFile = File.createTempFile("bluetooth_le_" + timeInMillis, ".csv", outputDir);
|
||||
outputFile.setReadable(true, false);
|
||||
generateFile(outputFile, getListAsCsv());
|
||||
i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(outputFile));
|
||||
i.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
|
||||
i.putExtra(Intent.EXTRA_EMAIL, new String[]{to});
|
||||
i.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
i.putExtra(Intent.EXTRA_TEXT, message);
|
||||
context.startActivity(Intent.createChooser(i, context.getString(R.string.exporter_email_device_list_picker_text)));
|
||||
@@ -178,5 +157,24 @@ public class BluetoothLeDeviceStore {
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static FileWriter generateFile(final File file, final String contents) {
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(file);
|
||||
writer.append(contents);
|
||||
writer.flush();
|
||||
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package uk.co.alt236.btlescan.services;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Service;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
@@ -33,247 +31,243 @@ import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Service for managing connection and data communication with a GATT server hosted on a
|
||||
* given Bluetooth LE device.
|
||||
*/
|
||||
public class BluetoothLeService extends Service {
|
||||
private final static String TAG = BluetoothLeService.class.getSimpleName();
|
||||
public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
|
||||
public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
|
||||
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
|
||||
public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
|
||||
public final static String EXTRA_DATA_RAW = "com.example.bluetooth.le.EXTRA_DATA_RAW";
|
||||
public final static String EXTRA_UUID_CHAR = "com.example.bluetooth.le.EXTRA_UUID_CHAR";
|
||||
private final static String TAG = BluetoothLeService.class.getSimpleName();
|
||||
private static final int STATE_DISCONNECTED = 0;
|
||||
private static final int STATE_CONNECTING = 1;
|
||||
private static final int STATE_CONNECTED = 2;
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
private BluetoothManager mBluetoothManager;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private String mBluetoothDeviceAddress;
|
||||
private BluetoothGatt mBluetoothGatt;
|
||||
private int mConnectionState = STATE_DISCONNECTED;
|
||||
// Implements callback methods for GATT events that the app cares about. For example,
|
||||
// connection change and services discovered.
|
||||
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
|
||||
@Override
|
||||
public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
|
||||
}
|
||||
|
||||
private BluetoothManager mBluetoothManager;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private String mBluetoothDeviceAddress;
|
||||
private BluetoothGatt mBluetoothGatt;
|
||||
private int mConnectionState = STATE_DISCONNECTED;
|
||||
@Override
|
||||
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int STATE_DISCONNECTED = 0;
|
||||
private static final int STATE_CONNECTING = 1;
|
||||
private static final int STATE_CONNECTED = 2;
|
||||
@Override
|
||||
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
|
||||
final String intentAction;
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
intentAction = ACTION_GATT_CONNECTED;
|
||||
mConnectionState = STATE_CONNECTED;
|
||||
broadcastUpdate(intentAction);
|
||||
Log.i(TAG, "Connected to GATT server.");
|
||||
// Attempts to discover services after successful connection.
|
||||
Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
|
||||
|
||||
public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
|
||||
public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
|
||||
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
|
||||
public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
|
||||
public final static String EXTRA_DATA_RAW = "com.example.bluetooth.le.EXTRA_DATA_RAW";
|
||||
public final static String EXTRA_UUID_CHAR = "com.example.bluetooth.le.EXTRA_UUID_CHAR";
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
intentAction = ACTION_GATT_DISCONNECTED;
|
||||
mConnectionState = STATE_DISCONNECTED;
|
||||
Log.i(TAG, "Disconnected from GATT server.");
|
||||
broadcastUpdate(intentAction);
|
||||
}
|
||||
}
|
||||
|
||||
// Implements callback methods for GATT events that the app cares about. For example,
|
||||
// connection change and services discovered.
|
||||
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
|
||||
@Override
|
||||
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
|
||||
final String intentAction;
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
intentAction = ACTION_GATT_CONNECTED;
|
||||
mConnectionState = STATE_CONNECTED;
|
||||
broadcastUpdate(intentAction);
|
||||
Log.i(TAG, "Connected to GATT server.");
|
||||
// Attempts to discover services after successful connection.
|
||||
Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
|
||||
@Override
|
||||
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
|
||||
} else {
|
||||
Log.w(TAG, "onServicesDiscovered received: " + status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
intentAction = ACTION_GATT_DISCONNECTED;
|
||||
mConnectionState = STATE_DISCONNECTED;
|
||||
Log.i(TAG, "Disconnected from GATT server.");
|
||||
broadcastUpdate(intentAction);
|
||||
}
|
||||
}
|
||||
private void broadcastUpdate(final String action) {
|
||||
final Intent intent = new Intent(action);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
|
||||
} else {
|
||||
Log.w(TAG, "onServicesDiscovered received: " + status);
|
||||
}
|
||||
}
|
||||
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
|
||||
final Intent intent = new Intent(action);
|
||||
intent.putExtra(EXTRA_UUID_CHAR, characteristic.getUuid().toString());
|
||||
|
||||
@Override
|
||||
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
|
||||
}
|
||||
}
|
||||
// Always try to add the RAW value
|
||||
final byte[] data = characteristic.getValue();
|
||||
if (data != null && data.length > 0) {
|
||||
intent.putExtra(EXTRA_DATA_RAW, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
|
||||
}
|
||||
};
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private void broadcastUpdate(final String action) {
|
||||
final Intent intent = new Intent(action);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
/**
|
||||
* After using a given BLE device, the app must call this method to ensure resources are
|
||||
* released properly.
|
||||
*/
|
||||
public void close() {
|
||||
if (mBluetoothGatt == null) {
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.close();
|
||||
mBluetoothGatt = null;
|
||||
}
|
||||
|
||||
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
|
||||
final Intent intent = new Intent(action);
|
||||
intent.putExtra(EXTRA_UUID_CHAR, characteristic.getUuid().toString());
|
||||
/**
|
||||
* Connects to the GATT server hosted on the Bluetooth LE device.
|
||||
*
|
||||
* @param address The device address of the destination device.
|
||||
* @return Return true if the connection is initiated successfully. The connection result
|
||||
* is reported asynchronously through the
|
||||
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
|
||||
* callback.
|
||||
*/
|
||||
public boolean connect(final String address) {
|
||||
if (mBluetoothAdapter == null || address == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always try to add the RAW value
|
||||
final byte[] data = characteristic.getValue();
|
||||
if (data != null && data.length > 0) {
|
||||
intent.putExtra(EXTRA_DATA_RAW, data);
|
||||
}
|
||||
// Previously connected device. Try to reconnect.
|
||||
if (mBluetoothDeviceAddress != null
|
||||
&& address.equals(mBluetoothDeviceAddress)
|
||||
&& mBluetoothGatt != null) {
|
||||
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
|
||||
if (mBluetoothGatt.connect()) {
|
||||
mConnectionState = STATE_CONNECTING;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
public BluetoothLeService getService() {
|
||||
return BluetoothLeService.this;
|
||||
}
|
||||
}
|
||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
|
||||
if (device == null) {
|
||||
Log.w(TAG, "Device not found. Unable to connect.");
|
||||
return false;
|
||||
}
|
||||
// We want to directly connect to the device, so we are setting the autoConnect
|
||||
// parameter to false.
|
||||
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
|
||||
Log.d(TAG, "Trying to create a new connection.");
|
||||
mBluetoothDeviceAddress = address;
|
||||
mConnectionState = STATE_CONNECTING;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(final Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
/**
|
||||
* Disconnects an existing connection or cancel a pending connection. The disconnection result
|
||||
* is reported asynchronously through the
|
||||
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
|
||||
* callback.
|
||||
*/
|
||||
public void disconnect() {
|
||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onUnbind(final Intent intent) {
|
||||
// After using a given device, you should make sure that BluetoothGatt.close() is called
|
||||
// such that resources are cleaned up properly. In this particular example, close() is
|
||||
// invoked when the UI is disconnected from the Service.
|
||||
close();
|
||||
return super.onUnbind(intent);
|
||||
}
|
||||
/**
|
||||
* Retrieves a list of supported GATT services on the connected device. This should be
|
||||
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
|
||||
*
|
||||
* @return A {@code List} of supported services.
|
||||
*/
|
||||
public List<BluetoothGattService> getSupportedGattServices() {
|
||||
if (mBluetoothGatt == null) return null;
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
return mBluetoothGatt.getServices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a reference to the local Bluetooth adapter.
|
||||
*
|
||||
* @return Return true if the initialization is successful.
|
||||
*/
|
||||
public boolean initialize() {
|
||||
// For API level 18 and above, get a reference to BluetoothAdapter through
|
||||
// BluetoothManager.
|
||||
if (mBluetoothManager == null) {
|
||||
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
if (mBluetoothManager == null) {
|
||||
Log.e(TAG, "Unable to initialize BluetoothManager.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Initializes a reference to the local Bluetooth adapter.
|
||||
*
|
||||
* @return Return true if the initialization is successful.
|
||||
*/
|
||||
public boolean initialize() {
|
||||
// For API level 18 and above, get a reference to BluetoothAdapter through
|
||||
// BluetoothManager.
|
||||
if (mBluetoothManager == null) {
|
||||
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
if (mBluetoothManager == null) {
|
||||
Log.e(TAG, "Unable to initialize BluetoothManager.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mBluetoothAdapter = mBluetoothManager.getAdapter();
|
||||
if (mBluetoothAdapter == null) {
|
||||
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
|
||||
return false;
|
||||
}
|
||||
mBluetoothAdapter = mBluetoothManager.getAdapter();
|
||||
if (mBluetoothAdapter == null) {
|
||||
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the GATT server hosted on the Bluetooth LE device.
|
||||
*
|
||||
* @param address The device address of the destination device.
|
||||
*
|
||||
* @return Return true if the connection is initiated successfully. The connection result
|
||||
* is reported asynchronously through the
|
||||
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
|
||||
* callback.
|
||||
*/
|
||||
public boolean connect(final String address) {
|
||||
if (mBluetoothAdapter == null || address == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public IBinder onBind(final Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
// Previously connected device. Try to reconnect.
|
||||
if (mBluetoothDeviceAddress != null
|
||||
&& address.equals(mBluetoothDeviceAddress)
|
||||
&& mBluetoothGatt != null) {
|
||||
@Override
|
||||
public boolean onUnbind(final Intent intent) {
|
||||
// After using a given device, you should make sure that BluetoothGatt.close() is called
|
||||
// such that resources are cleaned up properly. In this particular example, close() is
|
||||
// invoked when the UI is disconnected from the Service.
|
||||
close();
|
||||
return super.onUnbind(intent);
|
||||
}
|
||||
|
||||
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
|
||||
if (mBluetoothGatt.connect()) {
|
||||
mConnectionState = STATE_CONNECTING;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
|
||||
* asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
|
||||
* callback.
|
||||
*
|
||||
* @param characteristic The characteristic to read from.
|
||||
*/
|
||||
public void readCharacteristic(final BluetoothGattCharacteristic characteristic) {
|
||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.readCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
|
||||
if (device == null) {
|
||||
Log.w(TAG, "Device not found. Unable to connect.");
|
||||
return false;
|
||||
}
|
||||
// We want to directly connect to the device, so we are setting the autoConnect
|
||||
// parameter to false.
|
||||
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
|
||||
Log.d(TAG, "Trying to create a new connection.");
|
||||
mBluetoothDeviceAddress = address;
|
||||
mConnectionState = STATE_CONNECTING;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Enables or disables notification on a give characteristic.
|
||||
*
|
||||
* @param characteristic Characteristic to act on.
|
||||
* @param enabled If true, enable notification. False otherwise.
|
||||
*/
|
||||
public void setCharacteristicNotification(final BluetoothGattCharacteristic characteristic, final boolean enabled) {
|
||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects an existing connection or cancel a pending connection. The disconnection result
|
||||
* is reported asynchronously through the
|
||||
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
|
||||
* callback.
|
||||
*/
|
||||
public void disconnect() {
|
||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* After using a given BLE device, the app must call this method to ensure resources are
|
||||
* released properly.
|
||||
*/
|
||||
public void close() {
|
||||
if (mBluetoothGatt == null) {
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.close();
|
||||
mBluetoothGatt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
|
||||
* asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
|
||||
* callback.
|
||||
*
|
||||
* @param characteristic The characteristic to read from.
|
||||
*/
|
||||
public void readCharacteristic(final BluetoothGattCharacteristic characteristic) {
|
||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.readCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables notification on a give characteristic.
|
||||
*
|
||||
* @param characteristic Characteristic to act on.
|
||||
* @param enabled If true, enable notification. False otherwise.
|
||||
*/
|
||||
public void setCharacteristicNotification(final BluetoothGattCharacteristic characteristic, final boolean enabled) {
|
||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||
return;
|
||||
}
|
||||
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of supported GATT services on the connected device. This should be
|
||||
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
|
||||
*
|
||||
* @return A {@code List} of supported services.
|
||||
*/
|
||||
public List<BluetoothGattService> getSupportedGattServices() {
|
||||
if (mBluetoothGatt == null) return null;
|
||||
|
||||
return mBluetoothGatt.getServices();
|
||||
}
|
||||
public class LocalBinder extends Binder {
|
||||
public BluetoothLeService getService() {
|
||||
return BluetoothLeService.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,40 +5,42 @@ import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
public class BluetoothLeScanner {
|
||||
private final Handler mHandler;
|
||||
private final BluetoothAdapter.LeScanCallback mLeScanCallback;
|
||||
private final BluetoothUtils mBluetoothUtils;
|
||||
private boolean mScanning;
|
||||
|
||||
public BluetoothLeScanner(final BluetoothAdapter.LeScanCallback leScanCallback, final BluetoothUtils bluetoothUtils){
|
||||
mHandler = new Handler();
|
||||
mLeScanCallback = leScanCallback;
|
||||
mBluetoothUtils = bluetoothUtils;
|
||||
}
|
||||
|
||||
public boolean isScanning() {
|
||||
return mScanning;
|
||||
}
|
||||
private final Handler mHandler;
|
||||
private final BluetoothAdapter.LeScanCallback mLeScanCallback;
|
||||
private final BluetoothUtils mBluetoothUtils;
|
||||
private boolean mScanning;
|
||||
|
||||
public void scanLeDevice(final int duration, final boolean enable) {
|
||||
public BluetoothLeScanner(final BluetoothAdapter.LeScanCallback leScanCallback, final BluetoothUtils bluetoothUtils) {
|
||||
mHandler = new Handler();
|
||||
mLeScanCallback = leScanCallback;
|
||||
mBluetoothUtils = bluetoothUtils;
|
||||
}
|
||||
|
||||
public boolean isScanning() {
|
||||
return mScanning;
|
||||
}
|
||||
|
||||
public void scanLeDevice(final int duration, final boolean enable) {
|
||||
if (enable) {
|
||||
if(mScanning){return;}
|
||||
Log.d("TAG", "~ Starting Scan");
|
||||
if (mScanning) {
|
||||
return;
|
||||
}
|
||||
Log.d("TAG", "~ Starting Scan");
|
||||
// Stops scanning after a pre-defined scan period.
|
||||
if(duration > 0){
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d("TAG", "~ Stopping Scan (timeout)");
|
||||
mScanning = false;
|
||||
mBluetoothUtils.getBluetoothAdapter().stopLeScan(mLeScanCallback);
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
if (duration > 0) {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d("TAG", "~ Stopping Scan (timeout)");
|
||||
mScanning = false;
|
||||
mBluetoothUtils.getBluetoothAdapter().stopLeScan(mLeScanCallback);
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
mScanning = true;
|
||||
mBluetoothUtils.getBluetoothAdapter().startLeScan(mLeScanCallback);
|
||||
} else {
|
||||
Log.d("TAG", "~ Stopping Scan");
|
||||
Log.d("TAG", "~ Stopping Scan");
|
||||
mScanning = false;
|
||||
mBluetoothUtils.getBluetoothAdapter().stopLeScan(mLeScanCallback);
|
||||
}
|
||||
|
||||
@@ -8,37 +8,36 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
public final class BluetoothUtils {
|
||||
private final Activity mActivity;
|
||||
private final BluetoothAdapter mBluetoothAdapter;
|
||||
public final static int REQUEST_ENABLE_BT = 2001;
|
||||
private final Activity mActivity;
|
||||
private final BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
public final static int REQUEST_ENABLE_BT = 2001;
|
||||
|
||||
public BluetoothUtils(final Activity activity){
|
||||
mActivity = activity;
|
||||
final BluetoothManager btManager = (BluetoothManager) mActivity.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
mBluetoothAdapter = btManager.getAdapter();
|
||||
}
|
||||
|
||||
public void askUserToEnableBluetoothIfNeeded(){
|
||||
if (isBluetoothLeSupported() && (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())) {
|
||||
final Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
|
||||
}
|
||||
}
|
||||
|
||||
public BluetoothAdapter getBluetoothAdapter(){
|
||||
return mBluetoothAdapter;
|
||||
}
|
||||
|
||||
public boolean isBluetoothLeSupported(){
|
||||
return mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
|
||||
}
|
||||
|
||||
public boolean isBluetoothOn(){
|
||||
if (mBluetoothAdapter == null) {
|
||||
return false;
|
||||
} else {
|
||||
return mBluetoothAdapter.isEnabled();
|
||||
}
|
||||
}
|
||||
public BluetoothUtils(final Activity activity) {
|
||||
mActivity = activity;
|
||||
final BluetoothManager btManager = (BluetoothManager) mActivity.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
mBluetoothAdapter = btManager.getAdapter();
|
||||
}
|
||||
|
||||
public void askUserToEnableBluetoothIfNeeded() {
|
||||
if (isBluetoothLeSupported() && (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())) {
|
||||
final Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
|
||||
}
|
||||
}
|
||||
|
||||
public BluetoothAdapter getBluetoothAdapter() {
|
||||
return mBluetoothAdapter;
|
||||
}
|
||||
|
||||
public boolean isBluetoothLeSupported() {
|
||||
return mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
|
||||
}
|
||||
|
||||
public boolean isBluetoothOn() {
|
||||
if (mBluetoothAdapter == null) {
|
||||
return false;
|
||||
} else {
|
||||
return mBluetoothAdapter.isEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@ 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";
|
||||
public static final DecimalFormat DOUBLE_TWO_DIGIT_ACCURACY = new DecimalFormat("#.##");
|
||||
public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
}
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
package uk.co.alt236.btlescan.util;
|
||||
|
||||
public class CsvWriterHelper {
|
||||
private static final String QUOTE = "\"";
|
||||
public static String addStuff(final Integer text){
|
||||
return QUOTE + text + QUOTE + ",";
|
||||
}
|
||||
private static final String QUOTE = "\"";
|
||||
|
||||
public static String addStuff(final Long text){
|
||||
return QUOTE + text + QUOTE + ",";
|
||||
}
|
||||
public static String addStuff(final Integer text) {
|
||||
return QUOTE + text + QUOTE + ",";
|
||||
}
|
||||
|
||||
public static String addStuff(final boolean value){
|
||||
return QUOTE + value + QUOTE + ",";
|
||||
}
|
||||
|
||||
public static String addStuff(String text){
|
||||
if(text == null){text = "<blank>";}
|
||||
text = text.replace(QUOTE, "'");
|
||||
public static String addStuff(final Long text) {
|
||||
return QUOTE + text + QUOTE + ",";
|
||||
}
|
||||
|
||||
return QUOTE + text.trim() + QUOTE + ",";
|
||||
}
|
||||
public static String addStuff(final boolean value) {
|
||||
return QUOTE + value + QUOTE + ",";
|
||||
}
|
||||
|
||||
public static String addStuff(String text) {
|
||||
if (text == null) {
|
||||
text = "<blank>";
|
||||
}
|
||||
text = text.replace(QUOTE, "'");
|
||||
|
||||
return QUOTE + text.trim() + QUOTE + ",";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class TimeFormatter {
|
||||
private final static String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
|
||||
private final static SimpleDateFormat ISO_FORMATTER = new UtcDateFormatter(ISO_FORMAT, Locale.US);
|
||||
private final static String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
|
||||
private final static SimpleDateFormat ISO_FORMATTER = new UtcDateFormatter(ISO_FORMAT, Locale.US);
|
||||
|
||||
public static String getIsoDateTime(final Date date){
|
||||
return ISO_FORMATTER.format(date);
|
||||
}
|
||||
public static String getIsoDateTime(final Date date) {
|
||||
return ISO_FORMATTER.format(date);
|
||||
}
|
||||
|
||||
public static String getIsoDateTime(final long millis){
|
||||
return getIsoDateTime(new Date(millis));
|
||||
}
|
||||
public static String getIsoDateTime(final long millis) {
|
||||
return getIsoDateTime(new Date(millis));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,74 @@
|
||||
/*******************************************************************************
|
||||
/**
|
||||
* ****************************************************************************
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
||||
*
|
||||
* <p/>
|
||||
* GenieConnect Ltd. ("COMPANY") CONFIDENTIAL
|
||||
* Unpublished Copyright (c) 2010-2013 GenieConnect Ltd., All Rights Reserved.
|
||||
*
|
||||
* <p/>
|
||||
* NOTICE:
|
||||
* All information contained herein is, and remains the property of COMPANY.
|
||||
* The intellectual and technical concepts contained herein are proprietary to
|
||||
* COMPANY and may be covered by U.S. and Foreign Patents, patents in process, and
|
||||
* are protected by trade secret or copyright law. Dissemination of this
|
||||
* information or reproduction of this material is strictly forbidden unless prior
|
||||
* written permission is obtained from COMPANY. Access to the source code
|
||||
* contained herein is hereby forbidden to anyone except current COMPANY employees,
|
||||
* All information contained herein is, and remains the property of COMPANY.
|
||||
* The intellectual and technical concepts contained herein are proprietary to
|
||||
* COMPANY and may be covered by U.S. and Foreign Patents, patents in process, and
|
||||
* are protected by trade secret or copyright law. Dissemination of this
|
||||
* information or reproduction of this material is strictly forbidden unless prior
|
||||
* written permission is obtained from COMPANY. Access to the source code
|
||||
* contained herein is hereby forbidden to anyone except current COMPANY employees,
|
||||
* managers or contractors who have executed Confidentiality and Non-disclosure
|
||||
* agreements explicitly covering such access.
|
||||
*
|
||||
* The copyright notice above does not evidence any actual or intended publication
|
||||
* or disclosure of this source code, which includes information that is
|
||||
* <p/>
|
||||
* The copyright notice above does not evidence any actual or intended publication
|
||||
* or disclosure of this source code, which includes information that is
|
||||
* confidential and/or proprietary, and is a trade secret, of COMPANY.
|
||||
*
|
||||
* ANY REPRODUCTION, MODIFICATION, DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC
|
||||
* DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS WRITTEN
|
||||
* CONSENT OF COMPANY IS STRICTLY PROHIBITED, AND IN VIOLATION OF APPLICABLE LAWS
|
||||
* AND INTERNATIONAL TREATIES. THE RECEIPT OR POSSESSION OF THIS SOURCE CODE
|
||||
* AND/OR RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE,
|
||||
* DISCLOSE OR DISTRIBUTE ITS CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING
|
||||
* <p/>
|
||||
* ANY REPRODUCTION, MODIFICATION, DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC
|
||||
* DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS WRITTEN
|
||||
* CONSENT OF COMPANY IS STRICTLY PROHIBITED, AND IN VIOLATION OF APPLICABLE LAWS
|
||||
* AND INTERNATIONAL TREATIES. THE RECEIPT OR POSSESSION OF THIS SOURCE CODE
|
||||
* AND/OR RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE,
|
||||
* DISCLOSE OR DISTRIBUTE ITS CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING
|
||||
* THAT IT MAY DESCRIBE, IN WHOLE OR IN PART.
|
||||
******************************************************************************/
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package uk.co.alt236.btlescan.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
public class UtcDateFormatter extends java.text.SimpleDateFormat {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public class UtcDateFormatter extends java.text.SimpleDateFormat{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TIME_ZONE_STRING = "UTC";
|
||||
private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone(TIME_ZONE_STRING);
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public UtcDateFormatter(final String template){
|
||||
super(template);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public UtcDateFormatter(final String template, final DateFormatSymbols symbols){
|
||||
super(template, symbols);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
public UtcDateFormatter(final String template, final Locale locale){
|
||||
super(template, locale);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will throw an UnsupportedOperationException.
|
||||
* You are not be able to change the TimeZone of this object
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
|
||||
*/
|
||||
@Override
|
||||
public void setTimeZone(final TimeZone timezone){
|
||||
throw new UnsupportedOperationException("This SimpleDateFormat can only be in " + TIME_ZONE_STRING);
|
||||
}
|
||||
private static final String TIME_ZONE_STRING = "UTC";
|
||||
private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone(TIME_ZONE_STRING);
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public UtcDateFormatter(final String template) {
|
||||
super(template);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public UtcDateFormatter(final String template, final DateFormatSymbols symbols) {
|
||||
super(template, symbols);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
public UtcDateFormatter(final String template, final Locale locale) {
|
||||
super(template, locale);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will throw an UnsupportedOperationException.
|
||||
* You are not be able to change the TimeZone of this object
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
|
||||
*/
|
||||
@Override
|
||||
public void setTimeZone(final TimeZone timezone) {
|
||||
throw new UnsupportedOperationException("This SimpleDateFormat can only be in " + TIME_ZONE_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="56dp" >
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="56dp">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center" />
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,15 +1,14 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
android:layout_height="wrap_content">
|
||||
</ListView>
|
||||
</RelativeLayout>
|
||||
@@ -15,13 +15,13 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
|
||||
<GridLayout
|
||||
android:id="@+id/deviceInformation"
|
||||
@@ -29,27 +29,27 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:columnCount="2"
|
||||
android:useDefaultMargins="true" >
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_device_address" />
|
||||
android:text="@string/label_device_address"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_address"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_state" />
|
||||
android:text="@string/label_state"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_state"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
</GridLayout>
|
||||
|
||||
<View
|
||||
@@ -57,7 +57,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_below="@id/deviceInformation"
|
||||
android:background="@android:color/holo_blue_dark" />
|
||||
android:background="@android:color/holo_blue_dark"/>
|
||||
|
||||
<GridLayout
|
||||
android:id="@+id/gattInformation"
|
||||
@@ -65,47 +65,47 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:columnCount="2"
|
||||
android:useDefaultMargins="true" >
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_uuid" />
|
||||
android:text="@string/label_uuid"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uuid"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_desc" />
|
||||
android:text="@string/label_desc"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_as_string" />
|
||||
android:text="@string/label_as_string"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/data_as_string"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_as_array" />
|
||||
android:text="@string/label_as_array"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/data_as_array"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
</GridLayout>
|
||||
|
||||
<View
|
||||
@@ -113,13 +113,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_above="@id/gattInformation"
|
||||
android:background="@android:color/holo_blue_dark" />
|
||||
android:background="@android:color/holo_blue_dark"/>
|
||||
|
||||
<ExpandableListView
|
||||
android:id="@+id/gatt_services_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_above="@id/lowerSepparator"
|
||||
android:layout_below="@id/upperSepparator" />
|
||||
android:layout_below="@id/upperSepparator"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -1,20 +1,20 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context=".MainActivity" >
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<GridLayout
|
||||
android:id="@+id/gridLayout1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin" >
|
||||
android:paddingBottom="@dimen/activity_vertical_margin">
|
||||
|
||||
<TextView
|
||||
android:layout_column="0"
|
||||
@@ -22,7 +22,7 @@
|
||||
android:layout_row="0"
|
||||
android:text="@string/label_bluetooth_le_status"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBluetoothLe"
|
||||
@@ -33,7 +33,7 @@
|
||||
android:layout_row="0"
|
||||
android:gravity="right"
|
||||
android:text="@string/not_supported"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -43,7 +43,7 @@
|
||||
android:layout_row="1"
|
||||
android:text="@string/label_bluetooth_status"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBluetoothStatus"
|
||||
@@ -54,59 +54,59 @@
|
||||
android:layout_row="1"
|
||||
android:gravity="right"
|
||||
android:text="@string/off"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
</GridLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/upperSepparator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/holo_blue_dark" />
|
||||
android:background="@android:color/holo_blue_dark"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/infoContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/lowerSepparator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/holo_blue_dark" />
|
||||
android:background="@android:color/holo_blue_dark"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvItemCount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/formatter_item_count" />
|
||||
android:text="@string/formatter_item_count"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/listContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_above="@id/infoContainer"
|
||||
android:orientation="vertical" >
|
||||
android:layout_alignParentTop="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
android:text="@string/no_data" />
|
||||
android:text="@string/no_data"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
@@ -15,34 +15,34 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="horizontal" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_icon"
|
||||
android:paddingTop="5dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:src="@drawable/ic_bluetooth" />
|
||||
android:paddingTop="5dp"
|
||||
android:src="@drawable/ic_bluetooth"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp" />
|
||||
android:textSize="24sp"/>
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2" >
|
||||
android:columnCount="2">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -50,14 +50,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_mac"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_address"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:typeface="monospace" />
|
||||
android:typeface="monospace"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -65,14 +65,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="Updated:"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_last_update"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -80,14 +80,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_rssi"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_rssi"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
</GridLayout>
|
||||
|
||||
<GridLayout
|
||||
@@ -95,7 +95,7 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/light_gray"
|
||||
android:columnCount="4" >
|
||||
android:columnCount="4">
|
||||
|
||||
<!-- ROW 1 -->
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_uuid"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_uuid"
|
||||
@@ -113,7 +113,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnSpan="3"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<!-- ROW 2 -->
|
||||
|
||||
@@ -123,14 +123,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_major"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_major"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -139,14 +139,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_minor"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_minor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<!-- ROW 3 -->
|
||||
|
||||
@@ -156,14 +156,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_tx_power"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_tx_power"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -172,14 +172,14 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_distance"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_distance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<!-- ROW 4 -->
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
android:paddingRight="5dp"
|
||||
android:text="Descriptor:"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_distance_descriptor"
|
||||
@@ -197,7 +197,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnSpan="3"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"/>
|
||||
</GridLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:useDefaultMargins="true" >
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_as_string" />
|
||||
android:text="@string/label_as_string"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/data_as_string"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_as_array" />
|
||||
android:text="@string/label_as_array"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/data_as_array"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
</GridLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,56 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:useDefaultMargins="true" >
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_device_name" />
|
||||
android:text="@string/label_device_name"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceName"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_device_address" />
|
||||
android:text="@string/label_device_address"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceAddress"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_device_class" />
|
||||
android:text="@string/label_device_class"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceClass"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_bonding_state" />
|
||||
android:text="@string/label_bonding_state"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceBondingState"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
</GridLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
@@ -13,11 +13,11 @@
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@android:color/holo_blue_dark"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/holo_blue_dark" />
|
||||
android:background="@android:color/holo_blue_dark"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,76 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:useDefaultMargins="true" >
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_company_id" />
|
||||
android:text="@string/label_company_id"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/companyId"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_advertisement" />
|
||||
android:text="@string/label_advertisement"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/advertisement"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_uuid" />
|
||||
android:text="@string/label_uuid"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uuid"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_major" />
|
||||
android:text="@string/label_major"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/major"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_minor" />
|
||||
android:text="@string/label_minor"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/minor"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_tx_power" />
|
||||
android:text="@string/label_tx_power"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txpower"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
</GridLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,66 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:useDefaultMargins="true" >
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_first_timestamp" />
|
||||
android:text="@string/label_first_timestamp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/firstTimestamp"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_first_rssi" />
|
||||
android:text="@string/label_first_rssi"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/firstRssi"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_last_timestamp" />
|
||||
android:text="@string/label_last_timestamp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lastTimestamp"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_last_rssi" />
|
||||
android:text="@string/label_last_rssi"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lastRssi"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
|
||||
<TextView
|
||||
style="@style/GridLayoutTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_running_average_rssi" />
|
||||
android:text="@string/label_running_average_rssi"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/runningAverageRssi"
|
||||
style="@style/GridLayoutDataTextView" />
|
||||
style="@style/GridLayoutDataTextView"/>
|
||||
</GridLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/data"
|
||||
style="@style/GridLayoutDataTextViewMonospace" />
|
||||
style="@style/GridLayoutDataTextViewMonospace"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -14,7 +14,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
|
||||
<item
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_refresh"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_refresh"
|
||||
@@ -33,9 +33,9 @@
|
||||
android:title="@string/menu_stop"/>
|
||||
<item
|
||||
android:id="@+id/menu_share"
|
||||
android:icon="@drawable/ic_action_share"
|
||||
android:orderInCategory="102"
|
||||
android:showAsAction="ifRoom"
|
||||
android:icon="@drawable/ic_action_share"
|
||||
android:title="@string/menu_share"/>
|
||||
<item
|
||||
android:id="@+id/menu_about"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<color name="light_gray">#66e0e0e0</color>
|
||||
<color name="light_gray">#66e0e0e0</color>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user