We now have a "connecting" state in the ControlActivity.

This commit is contained in:
Alexandros Schillings
2016-08-31 19:09:38 +01:00
parent 727f2d8953
commit 7f15ea3d1e
3 changed files with 135 additions and 49 deletions
@@ -39,22 +39,20 @@ import java.util.List;
*/
public class BluetoothLeService extends Service {
public final static String ACTION_GATT_CONNECTED = BluetoothLeService.class.getName() + ".ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_CONNECTING = BluetoothLeService.class.getName() + ".ACTION_GATT_CONNECTING";
public final static String ACTION_GATT_DISCONNECTED = BluetoothLeService.class.getName() + ".ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = BluetoothLeService.class.getName() + ".ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = BluetoothLeService.class.getName() + ".ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA_RAW = BluetoothLeService.class.getName() + ".EXTRA_DATA_RAW";
public final static String EXTRA_UUID_CHAR = BluetoothLeService.class.getName() + ".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;
private State 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() {
@@ -64,28 +62,35 @@ public class BluetoothLeService extends Service {
}
@Override
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
final String intentAction;
public void onConnectionStateChange(final BluetoothGatt gatt,
final int status,
final int newState) {
Log.d(TAG, "onConnectionStateChange: status=" + status + ", newState=" + newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
setConnectionState(State.CONNECTED, true);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
// Make sure we tidy up. On certain devices reusing a Gatt after a disconnection
// can cause problems.
disconnect();
setConnectionState(State.DISCONNECTED, true);
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
@@ -139,37 +144,73 @@ public class BluetoothLeService extends Service {
* callback.
*/
public boolean connect(final String address) {
final boolean retVal;
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
retVal = false;
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null
// Previously connected device. Try to reconnect.
} else if (mBluetoothDeviceAddress != null
&& address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
Log.d(TAG, "Connection attempt OK.");
setConnectionState(State.CONNECTING, true);
retVal = true;
} else {
return false;
Log.w(TAG, "Connection attempt failed.");
setConnectionState(State.DISCONNECTED, true);
retVal = false;
}
} else {
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
retVal = false;
} else {
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
Log.d(TAG, "Trying to create a new connection.");
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
mBluetoothDeviceAddress = address;
setConnectionState(State.CONNECTING, true);
retVal = true;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
return retVal;
}
private synchronized void setConnectionState(final State newState, final boolean broadCast) {
Log.i(TAG, "Setting internal state to " + newState);
mConnectionState = newState;
final String broadcastAction;
switch (newState) {
case CONNECTED:
broadcastAction = ACTION_GATT_CONNECTED;
break;
case CONNECTING:
broadcastAction = ACTION_GATT_CONNECTING;
break;
case DISCONNECTED:
broadcastAction = ACTION_GATT_DISCONNECTED;
break;
default:
throw new IllegalArgumentException("Unknown state: " + newState);
}
// 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;
if (broadCast) {
Log.i(TAG, "Broadcasting " + broadcastAction);
broadcastUpdate(broadcastAction);
}
}
/**
@@ -184,6 +225,9 @@ public class BluetoothLeService extends Service {
return;
}
mBluetoothGatt.disconnect();
// Reusing a Gatt after disconnecting can cause problems
mBluetoothGatt = null;
}
/**
@@ -271,4 +315,10 @@ public class BluetoothLeService extends Service {
return BluetoothLeService.this;
}
}
private enum State {
DISCONNECTED,
CONNECTING,
CONNECTED
}
}
@@ -121,7 +121,8 @@ public class DeviceControlActivity extends AppCompatActivity {
}
};
private BluetoothLeDevice mDevice;
private boolean mConnected = false;
private State mCurrentState = State.DISCONNECTED;
private String mExportString;
// Handles various events fired by the Service.
// ACTION_GATT_CONNECTED: connected to a GATT server.
@@ -134,14 +135,16 @@ public class DeviceControlActivity extends AppCompatActivity {
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);
updateConnectionState(State.CONNECTED);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
updateConnectionState(State.DISCONNECTED);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_CONNECTING.equals(action)) {
clearUI();
updateConnectionState(State.CONNECTING);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
displayGattServices(mBluetoothLeService.getSupportedGattServices());
@@ -159,6 +162,7 @@ public class DeviceControlActivity extends AppCompatActivity {
};
private void clearUI() {
mExportString = null;
mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
mGattUUID.setText(R.string.no_data);
mGattUUIDDesc.setText(R.string.no_data);
@@ -206,12 +210,26 @@ public class DeviceControlActivity extends AppCompatActivity {
@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);
switch (mCurrentState) {
case DISCONNECTED:
menu.findItem(R.id.menu_connect).setVisible(true);
menu.findItem(R.id.menu_disconnect).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(null);
break;
case CONNECTING:
menu.findItem(R.id.menu_connect).setVisible(false);
menu.findItem(R.id.menu_disconnect).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(R.layout.actionbar_progress_indeterminate);
break;
case CONNECTED:
menu.findItem(R.id.menu_connect).setVisible(false);
menu.findItem(R.id.menu_disconnect).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
break;
default:
throw new IllegalStateException("Don't know how to handle: " + mCurrentState);
}
if (mExportString == null) {
@@ -278,25 +296,35 @@ public class DeviceControlActivity extends AppCompatActivity {
}
}
private void updateConnectionState(final int resourceId) {
private void updateConnectionState(final State state) {
mCurrentState = state;
runOnUiThread(new Runnable() {
@Override
public void run() {
final int colourId;
final int resId;
switch (resourceId) {
case R.string.connected:
switch (state) {
case CONNECTED:
colourId = android.R.color.holo_green_dark;
resId = R.string.connected;
break;
case R.string.disconnected:
case DISCONNECTED:
colourId = android.R.color.holo_red_dark;
resId = R.string.disconnected;
break;
case CONNECTING:
colourId = android.R.color.black;
resId = R.string.connecting;
break;
default:
colourId = android.R.color.black;
resId = 0;
break;
}
mConnectionState.setText(resourceId);
mConnectionState.setText(resId);
mConnectionState.setTextColor(ContextCompat.getColor(DeviceControlActivity.this, colourId));
}
});
@@ -308,6 +336,7 @@ public class DeviceControlActivity extends AppCompatActivity {
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTING);
return intentFilter;
}
@@ -324,4 +353,10 @@ public class DeviceControlActivity extends AppCompatActivity {
intent.putExtra(DeviceControlActivity.EXTRA_DEVICE, device);
return intent;
}
private enum State {
DISCONNECTED,
CONNECTING,
CONNECTED
}
}
@@ -5,6 +5,7 @@
<string name="app_name">Bluetooth LE Scanner</string>
<string name="connected">Connected</string>
<string name="disconnected">Disconnected</string>
<string name="connecting">Connecting</string>
<string name="invalid_device_data">Invalid Device Data!</string>
<string name="no_data">No data</string>
<string name="not_supported">Not supported</string>