Bugs fixed in Proximity profile

This commit is contained in:
Aleksander Nowakowski
2016-10-19 12:13:57 +02:00
parent 3c8c13ff7e
commit 4bbd88b0e6
5 changed files with 131 additions and 33 deletions

View File

@@ -24,15 +24,12 @@ package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGatt;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import java.util.List; import java.util.List;
@@ -142,6 +139,8 @@ public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder
batteryView.setVisibility(View.VISIBLE); batteryView.setVisibility(View.VISIBLE);
batteryView.setText(batteryView.getResources().getString(R.string.battery, batteryValue)); batteryView.setText(batteryView.getResources().getString(R.string.battery, batteryValue));
batteryView.setAlpha(state == BluetoothGatt.STATE_CONNECTED ? 1.0f : 0.5f); batteryView.setAlpha(state == BluetoothGatt.STATE_CONNECTED ? 1.0f : 0.5f);
} else {
batteryView.setVisibility(View.GONE);
} }
} }
} }

View File

@@ -21,6 +21,7 @@
*/ */
package no.nordicsemi.android.nrftoolbox.proximity; package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
@@ -126,7 +127,10 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit
public void onLinklossOccur(final BluetoothDevice device) { public void onLinklossOccur(final BluetoothDevice device) {
if (mAdapter != null) if (mAdapter != null)
mAdapter.onDeviceStateChanged(device); mAdapter.onDeviceStateChanged(device);
showLinklossDialog(device.getName());
// The link loss may also be called when Bluetooth adapter was disabled
if (BluetoothAdapter.getDefaultAdapter().isEnabled())
showLinklossDialog(device.getName());
} }
@Override @Override

View File

@@ -32,6 +32,7 @@ import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import android.util.Log;
import java.util.UUID; import java.util.UUID;
@@ -60,10 +61,13 @@ public class ProximityServerManager {
private IDeviceLogger mLogger; private IDeviceLogger mLogger;
private Handler mHandler; private Handler mHandler;
private OnServerOpenCallback mOnServerOpenCallback; private OnServerOpenCallback mOnServerOpenCallback;
private boolean mServerReady;
public interface OnServerOpenCallback { public interface OnServerOpenCallback {
/** Method called when the GATT server was created and all services were added successfully. */ /** Method called when the GATT server was created and all services were added successfully. */
void onGattServerOpen(); void onGattServerOpen();
/** Method called when the GATT server failed to open and initialize services. -1 is returned when the server failed to start. */
void onGattServerFailed(final int error);
} }
public ProximityServerManager(final ProximityServerManagerCallbacks callbacks) { public ProximityServerManager(final ProximityServerManagerCallbacks callbacks) {
@@ -71,27 +75,96 @@ public class ProximityServerManager {
mCallbacks = callbacks; mCallbacks = callbacks;
} }
/**
* Sets the logger object. Logger is used to create logs in nRF Logger application.
* @param logger the logger object
*/
public void setLogger(final IDeviceLogger logger) { public void setLogger(final IDeviceLogger logger) {
mLogger = logger; mLogger = logger;
} }
/**
* Opens GATT server and creates 2 services: Link Loss Service and Immediate Alert Service.
* The callback is called when initialization is complete.
* @param context the context
* @param callback optional callback notifying when all services has been added
*/
public void openGattServer(final Context context, final OnServerOpenCallback callback) { public void openGattServer(final Context context, final OnServerOpenCallback callback) {
// Is the server already open?
if (mBluetoothGattServer != null) {
if (callback != null)
callback.onGattServerOpen();
return;
}
mOnServerOpenCallback = callback; mOnServerOpenCallback = callback;
final BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); final BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks); mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks);
addImmediateAlertService(); if (mBluetoothGattServer != null) {
// Start adding services one by one. The onServiceAdded method will be called when it completes.
addImmediateAlertService();
} else {
if (callback != null)
callback.onGattServerFailed(-1);
mOnServerOpenCallback = null;
}
} }
/**
* Returns true if GATT server was opened and configured correctly.
* False if hasn't been opened, was closed, of failed to start.
*/
public boolean isServerReady() {
return mServerReady;
}
/**
* Closes the GATT server. It will also disconnect all existing connections.
* If the service has already been closed, or hasn't been open, this method does nothing.
*/
public void closeGattServer() { public void closeGattServer() {
if (mBluetoothGattServer != null) { if (mBluetoothGattServer != null) {
mBluetoothGattServer.close(); mBluetoothGattServer.close();
mBluetoothGattServer = null; mBluetoothGattServer = null;
mOnServerOpenCallback = null; mOnServerOpenCallback = null;
mServerReady = false;
} }
} }
public void cancelConnection(final BluetoothDevice device) { /**
* This method notifies the Android that the Proximity profile will use the server connection to given device.
* If the server hasn't been open this method does nothing. The {@link #cancelConnection(BluetoothDevice)} method
* should be called when the connection is no longer used.
* @param device target device
*/
public void openConnection(final BluetoothDevice device) {
if (mBluetoothGattServer != null) {
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Creating server connection...");
mLogger.log(device, LogContract.Log.Level.DEBUG, "server.connect(device, autoConnect = true)");
mBluetoothGattServer.connect(device, true); // In proximity the autoConnect is true
}
}
/**
* Cancels the connection to the given device. This notifies Android that this profile will no longer
* use this connection and it can be disconnected. In practice, this method does not disconnect, so
* if the remote device decides still to use the phone's GATT server it will be able to do so.
* <p>This bug/feature can be tested using a proximity tag that does not release its connection when it got
* disconnected:
* <ol>
* <li>Connect to your Proximity Tag.</li>
* <li>Verify that the bidirectional connection works - test the FIND ME button in nRF Toolbox and
* the FIND PHONE button on the tag.</li>
* <li>Disconnect from the tag</li>
* <li>When the device disappear from the list of devices click the FIND PHONE button on the tag.
* Your phone should still trigger an alarm, as the connection tag-&gt;phone is still active.</li>
* </ol>
* In order to avoid this issue make sure that your tag disconnects gently from phone when it got disconnected itself.
* </p>
* @param device the device that will no longer be used
*/
public void cancelConnection(final BluetoothDevice device) {
if (mBluetoothGattServer != null) { if (mBluetoothGattServer != null) {
mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Cancelling server connection..."); mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Cancelling server connection...");
mLogger.log(device, LogContract.Log.Level.DEBUG, "server.cancelConnection(device)"); mLogger.log(device, LogContract.Log.Level.DEBUG, "server.cancelConnection(device)");
@@ -126,18 +199,28 @@ public class ProximityServerManager {
private final BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() { private final BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() {
@Override @Override
public void onServiceAdded(final int status, final BluetoothGattService service) { public void onServiceAdded(final int status, final BluetoothGattService service) {
// Adding another service from callback thread fails on Samsung S4 with Android 4.3 if (status == BluetoothGatt.GATT_SUCCESS) {
mHandler.post(new Runnable() { // Adding another service from callback thread fails on Samsung S4 with Android 4.3
@Override mHandler.post(new Runnable() {
public void run() { @Override
if (IMMEDIATE_ALERT_SERVICE_UUID.equals(service.getUuid())) { public void run() {
addLinklossService(); if (IMMEDIATE_ALERT_SERVICE_UUID.equals(service.getUuid())) {
} else if (mOnServerOpenCallback != null) { addLinklossService();
mOnServerOpenCallback.onGattServerOpen(); } else {
mOnServerOpenCallback = null; mServerReady = true;
// Both services has been added
if (mOnServerOpenCallback != null)
mOnServerOpenCallback.onGattServerOpen();
mOnServerOpenCallback = null;
}
} }
} });
}); } else {
Log.e(TAG, "GATT Server failed to add service, status: " + status);
if (mOnServerOpenCallback != null)
mOnServerOpenCallback.onGattServerFailed(status);
mOnServerOpenCallback = null;
}
} }
@Override @Override

View File

@@ -24,6 +24,7 @@ package no.nordicsemi.android.nrftoolbox.proximity;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -142,6 +143,9 @@ public class ProximityService extends BleMulticonnectProfileService implements P
@Override @Override
protected void onServiceCreated() { protected void onServiceCreated() {
mServerManager = new ProximityServerManager(this);
mServerManager.setLogger(mBinder);
initializeAlarm(); initializeAlarm();
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT)); registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
@@ -155,10 +159,8 @@ public class ProximityService extends BleMulticonnectProfileService implements P
public void onServiceStopped() { public void onServiceStopped() {
cancelNotifications(); cancelNotifications();
// GATT server might have not been created if Bluetooth was disabled // Close the GATT server. If it hasn't been opened this method does nothing
if (mServerManager != null) { mServerManager.closeGattServer();
mServerManager.closeGattServer();
}
unregisterReceiver(mDisconnectActionBroadcastReceiver); unregisterReceiver(mDisconnectActionBroadcastReceiver);
unregisterReceiver(mToggleAlarmActionBroadcastReceiver); unregisterReceiver(mToggleAlarmActionBroadcastReceiver);
@@ -169,29 +171,31 @@ public class ProximityService extends BleMulticonnectProfileService implements P
@Override @Override
protected void onBluetoothEnabled() { protected void onBluetoothEnabled() {
// Start the GATT Server only if Bluetooth is enabled // Start the GATT Server only if Bluetooth is enabled
mServerManager = new ProximityServerManager(this);
mServerManager.setLogger(mBinder);
mServerManager.openGattServer(this, new ProximityServerManager.OnServerOpenCallback() { mServerManager.openGattServer(this, new ProximityServerManager.OnServerOpenCallback() {
@Override @Override
public void onGattServerOpen() { public void onGattServerOpen() {
// We are now ready to reconnect devices // We are now ready to reconnect devices
ProximityService.super.onBluetoothEnabled(); ProximityService.super.onBluetoothEnabled();
} }
@Override
public void onGattServerFailed(final int error) {
mServerManager.closeGattServer();
showToast(getString(R.string.proximity_server_error, error));
}
}); });
} }
@Override @Override
protected void onBluetoothDisabled() { protected void onBluetoothDisabled() {
super.onBluetoothDisabled(); super.onBluetoothDisabled();
if (mServerManager != null) { // Close the GATT server
mServerManager.closeGattServer(); mServerManager.closeGattServer();
mServerManager = null;
}
} }
@Override @Override
protected void onRebind() { protected void onRebind() {
// when the activity rebinds to the service, remove the notification // When the activity rebinds to the service, remove the notification
cancelNotifications(); cancelNotifications();
} }
@@ -209,22 +213,30 @@ public class ProximityService extends BleMulticonnectProfileService implements P
} }
} }
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
super.onServicesDiscovered(device, optionalServicesFound);
mServerManager.openConnection(device);
}
@Override @Override
public void onLinklossOccur(final BluetoothDevice device) { public void onLinklossOccur(final BluetoothDevice device) {
mServerManager.cancelConnection(device);
stopAlarm(device); stopAlarm(device);
super.onLinklossOccur(device); super.onLinklossOccur(device);
if (!mBinded) { if (!mBinded) {
createBackgroundNotification(); createBackgroundNotification();
createLinklossNotification(device); if (BluetoothAdapter.getDefaultAdapter().isEnabled())
createLinklossNotification(device);
else
cancelNotification(device);
} }
} }
@Override @Override
public void onDeviceDisconnected(final BluetoothDevice device) { public void onDeviceDisconnected(final BluetoothDevice device) {
if (mServerManager != null) { mServerManager.cancelConnection(device);
mServerManager.cancelConnection(device);
}
stopAlarm(device); stopAlarm(device);
super.onDeviceDisconnected(device); super.onDeviceDisconnected(device);

View File

@@ -48,7 +48,7 @@
<string name="proximity_notification_linkloss_alert">%s is getting away!</string> <string name="proximity_notification_linkloss_alert">%s is getting away!</string>
<string name="proximity_devices_title">YOUR TAGS</string> <string name="proximity_devices_title">YOUR TAGS</string>
<string name="proximity_enable_server">GATT Server enabled</string> <string name="proximity_server_error">GATT Server failed to start (error %d).</string>
<string name="proximity_about_text">PROXIMITY profile allows you to connect to multiple Proximity sensors. <string name="proximity_about_text">PROXIMITY profile allows you to connect to multiple Proximity sensors.
\nYou can find your valuables attached with Proximity tag by pressing the Locate button next to your device. \nYou can find your valuables attached with Proximity tag by pressing the Locate button next to your device.