I am trying to adapt code from Bluetooth BLE developer starter kit to my own app (i.e this exact same code is working well on the example app).
But, I can't connect to any device, because, when I am pressing the Connect button (method onConnect), bluetooth_le_adapter is null.
I think that the bluetooth_le_adapter is not well initialized, and so, is null at startup.
Do you have any idea on how to fix this problem ? Thanks
PeripheralControlActivity.java:
public class PeripheralControlActivity extends Activity {
public static final String EXTRA_NAME = "name";
public static final String EXTRA_ID = "id";
private String device_name;
private String device_address;
private Timer mTimer;
private boolean sound_alarm_on_disconnect = false;
private int alert_level;
private boolean back_requested = false;
private boolean share_with_server = false;
private Switch share_switch;
private BleAdapterService bluetooth_le_adapter;
private final ServiceConnection service_connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
bluetooth_le_adapter = ((BleAdapterService.LocalBinder) service).getService();
bluetooth_le_adapter.setActivityHandler(message_handler);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
bluetooth_le_adapter = null;
}
};
private Handler message_handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle bundle;
String service_uuid = "";
String characteristic_uuid = "";
byte[] b = null;
switch (msg.what) {
case BleAdapterService.MESSAGE:
bundle = msg.getData();
String text = bundle.getString(BleAdapterService.PARCEL_TEXT);
showMsg(text);
break;
case BleAdapterService.GATT_CONNECTED:
((Button) PeripheralControlActivity.this
.findViewById(R.id.connectButton)).setEnabled(false);
((Button) PeripheralControlActivity.this.findViewById(R.id.noiseButton))
.setEnabled(true);
share_switch.setEnabled(true);
// we're connected
showMsg("CONNECTED");
/*AlarmManager am = AlarmManager.getInstance();
Log.d(Constants.TAG, "alarmIsSounding=" + am.alarmIsSounding());
if (am.alarmIsSounding()) {
Log.d(Constants.TAG, "Stopping alarm");
am.stopAlarm();
}*/
bluetooth_le_adapter.discoverServices();
break;
case BleAdapterService.GATT_DISCONNECT:
((Button) PeripheralControlActivity.this
.findViewById(R.id.connectButton)).setEnabled(true);
// we're disconnected
showMsg("DISCONNECTED");
// hide the rssi distance colored rectangle
((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle))
.setVisibility(View.INVISIBLE);
share_switch.setEnabled(false);
// disable the LOW/MID/HIGH alert level selection buttons
((Button) PeripheralControlActivity.this.findViewById(R.id.lowButton)).setEnabled(false);
((Button) PeripheralControlActivity.this.findViewById(R.id.midButton)).setEnabled(false);
((Button) PeripheralControlActivity.this.findViewById(R.id.highButton)).setEnabled(false);
// stop the rssi reading timer
stopTimer();
/*if (alert_level > 0) {
AlarmManager.getInstance().soundAlarm(getResources().openRawResourceFd(R.raw.alarm));
}*/
if (back_requested) {
PeripheralControlActivity.this.finish();
}
break;
case BleAdapterService.GATT_SERVICES_DISCOVERED:
// validate services and if ok....
List<BluetoothGattService> slist = bluetooth_le_adapter.getSupportedGattServices();
boolean link_loss_present = false;
boolean immediate_alert_present = false;
boolean tx_power_present = false;
boolean proximity_monitoring_present = false;
for (BluetoothGattService svc : slist) {
Log.d(Constants.TAG, "UUID=" + svc.getUuid().toString().toUpperCase() + " INSTANCE=" + svc.getInstanceId());
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.LINK_LOSS_SERVICE_UUID)) {
link_loss_present = true;
continue;
}
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.IMMEDIATE_ALERT_SERVICE_UUID)) {
immediate_alert_present = true;
continue;
}
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.TX_POWER_SERVICE_UUID)) {
tx_power_present = true;
continue;
}
if (svc.getUuid().toString().equalsIgnoreCase(BleAdapterService.PROXIMITY_MONITORING_SERVICE_UUID)) {
proximity_monitoring_present = true;
continue;
}
}
if (link_loss_present && immediate_alert_present && tx_power_present && proximity_monitoring_present) {
showMsg("Device has expected services");
// show the rssi distance colored rectangle
((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle))
.setVisibility(View.VISIBLE);
// enable the LOW/MID/HIGH alert level selection buttons
((Button) PeripheralControlActivity.this.findViewById(R.id.lowButton)).setEnabled(true);
((Button) PeripheralControlActivity.this.findViewById(R.id.midButton)).setEnabled(true);
((Button) PeripheralControlActivity.this.findViewById(R.id.highButton)).setEnabled(true);
showMsg("Reading alert_level");
bluetooth_le_adapter.readCharacteristic(
BleAdapterService.LINK_LOSS_SERVICE_UUID,
BleAdapterService.ALERT_LEVEL_CHARACTERISTIC);
} else {
showMsg("Device does not have expected GATT services");
}
break;
case BleAdapterService.GATT_REMOTE_RSSI:
bundle = msg.getData();
int rssi = bundle.getInt(BleAdapterService.PARCEL_RSSI);
PeripheralControlActivity.this.updateRssi(rssi);
break;
case BleAdapterService.GATT_CHARACTERISTIC_READ:
bundle = msg.getData();
Log.d(Constants.TAG, "Service=" + bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString().toUpperCase() + " Characteristic=" + bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString().toUpperCase());
if (bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString().toUpperCase()
.equals(BleAdapterService.ALERT_LEVEL_CHARACTERISTIC)
&& bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString().toUpperCase()
.equals(BleAdapterService.LINK_LOSS_SERVICE_UUID)) {
b = bundle.getByteArray(BleAdapterService.PARCEL_VALUE);
if (b.length > 0) {
PeripheralControlActivity.this.setAlertLevel((int) b[0]);
Log.d(Constants.TAG, "Current alert_level is set to: " + b[0]);
// show the rssi distance colored rectangle
((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle))
.setVisibility(View.VISIBLE);
// start off the rssi reading timer
startReadRssiTimer();
}
}
break;
case BleAdapterService.GATT_CHARACTERISTIC_WRITTEN:
bundle = msg.getData();
Log.d(Constants.TAG, "Service=" + bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString().toUpperCase() + " Characteristic=" + bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString().toUpperCase());
if (bundle.get(BleAdapterService.PARCEL_CHARACTERISTIC_UUID).toString()
.toUpperCase().equals(BleAdapterService.ALERT_LEVEL_CHARACTERISTIC)
&& bundle.get(BleAdapterService.PARCEL_SERVICE_UUID).toString()
.toUpperCase().equals(BleAdapterService.LINK_LOSS_SERVICE_UUID)) {
b = bundle.getByteArray(BleAdapterService.PARCEL_VALUE);
Log.d(Constants.TAG, "New alert_level set to: " + b[0]);
PeripheralControlActivity.this.setAlertLevel((int) b[0]);
}
break;
}
}
};
public void onLow(View view) {
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.LINK_LOSS_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, Constants.ALERT_LEVEL_LOW);
}
public void onMid(View view) {
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.LINK_LOSS_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, Constants.ALERT_LEVEL_MID);
}
public void onHigh(View view) {
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.LINK_LOSS_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, Constants.ALERT_LEVEL_HIGH);
}
public void onNoise(View view) {
byte[] al = new byte[1];
al[0] = (byte) alert_level;
bluetooth_le_adapter.writeCharacteristic(BleAdapterService.IMMEDIATE_ALERT_SERVICE_UUID, BleAdapterService.ALERT_LEVEL_CHARACTERISTIC, al);
}
public void onBackPressed() {
Log.d(Constants.TAG, "onBackPressed");
back_requested = true;
if (bluetooth_le_adapter.isConnected()) {
try {
bluetooth_le_adapter.disconnect();
} catch (Exception e) {
}
} else {
finish();
}
}
private void setAlertLevel(int alert_level) {
this.alert_level = alert_level;
((Button) this.findViewById(R.id.lowButton)).setTextColor(Color.parseColor("#000000"));
;
((Button) this.findViewById(R.id.midButton)).setTextColor(Color.parseColor("#000000"));
;
((Button) this.findViewById(R.id.highButton)).setTextColor(Color.parseColor("#000000"));
;
switch (alert_level) {
case 0:
((Button) this.findViewById(R.id.lowButton)).setTextColor(Color.parseColor("#FF0000"));
;
break;
case 1:
((Button) this.findViewById(R.id.midButton)).setTextColor(Color.parseColor("#FF0000"));
;
break;
case 2:
((Button) this.findViewById(R.id.highButton)).setTextColor(Color.parseColor("#FF0000"));
;
break;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_peripheral_control);
// read intent data
final Intent intent = getIntent();
device_name = intent.getStringExtra(EXTRA_NAME);
device_address = intent.getStringExtra(EXTRA_ID);
// show the device name
((TextView) this.findViewById(R.id.nameTextView)).setText("Device : " + device_name + " [" + device_address + "]");
// hide the coloured rectangle used to show green/amber/red rssi distance
((LinearLayout) this.findViewById(R.id.rectangle)).setVisibility(View.INVISIBLE);
// hide the coloured rectangle used to show green/amber/red rssi
// distance
((LinearLayout) this.findViewById(R.id.rectangle))
.setVisibility(View.INVISIBLE);
// disable the noise button
((Button) PeripheralControlActivity.this.findViewById(R.id.noiseButton))
.setEnabled(false);
// disable the LOW/MID/HIGH alert level selection buttons
((Button) this.findViewById(R.id.lowButton)).setEnabled(false);
((Button) this.findViewById(R.id.midButton)).setEnabled(false);
((Button) this.findViewById(R.id.highButton)).setEnabled(false);
share_switch = (Switch) this.findViewById(R.id.switch1);
share_switch.setEnabled(false);
share_switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (bluetooth_le_adapter != null) {
share_with_server = isChecked;
if (!isChecked && bluetooth_le_adapter.isConnected()) {
showMsg("Switched off sharing proximity data");
// write 0,0 to cause Arduino to switch off all LEDs
if (bluetooth_le_adapter.writeCharacteristic(
BleAdapterService.PROXIMITY_MONITORING_SERVICE_UUID,
BleAdapterService.CLIENT_PROXIMITY_CHARACTERISTIC,
new byte[]{0, 0})) {
} else {
showMsg("Failed to inform Arduino sharing has been disabled");
}
}
}
}
});
// connect to the Bluetooth adapter service
Intent gattServiceIntent = new Intent(this, BleAdapterService.class);
bindService(gattServiceIntent, service_connection, BIND_AUTO_CREATE);
showMsg("READY");
}
#Override
protected void onDestroy() {
super.onDestroy();
stopTimer();
unbindService(service_connection);
bluetooth_le_adapter = null;
}
private void showMsg(final String msg) {
Log.i(Constants.TAG, msg);
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.msgTextView)).setText(msg);
}
});
}
public void onConnect(View view) {
showMsg("onConnect");
if (bluetooth_le_adapter != null) {
if (bluetooth_le_adapter.connect(device_address)) {
((Button) PeripheralControlActivity.this
.findViewById(R.id.connectButton)).setEnabled(false);
} else {
showMsg("onConnect: failed to connect");
}
} else {
showMsg("onConnect: bluetooth_le_adapter=null");
}
}
private void startReadRssiTimer() {
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
#Override
public void run() {
bluetooth_le_adapter.readRemoteRssi();
}
}, 0, 2000);
}
private void stopTimer() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
private void updateRssi(int rssi) {
((TextView) findViewById(R.id.rssiTextView)).setText("RSSI = "
+ Integer.toString(rssi));
LinearLayout layout = ((LinearLayout) PeripheralControlActivity.this
.findViewById(R.id.rectangle));
byte proximity_band = 3;
if (rssi < -80) {
layout.setBackgroundColor(0xFFFF0000);
} else if (rssi < -50) {
layout.setBackgroundColor(0xFFFF8A01);
proximity_band = 2;
} else {
layout.setBackgroundColor(0xFF00FF00);
proximity_band = 1;
}
layout.invalidate();
if (share_with_server) {
if (bluetooth_le_adapter.writeCharacteristic(
BleAdapterService.PROXIMITY_MONITORING_SERVICE_UUID,
BleAdapterService.CLIENT_PROXIMITY_CHARACTERISTIC,
new byte[]{proximity_band, (byte) rssi})) {
showMsg("proximity data shared: proximity_band:" + proximity_band + ",rssi:" + rssi);
} else {
showMsg("Failed to share proximity data");
}
}
}
}
BleAdapterService.java
public class BleAdapterService extends Service {
private BluetoothAdapter bluetooth_adapter;
private BluetoothGatt bluetooth_gatt;
private BluetoothManager bluetooth_manager;
private Handler activity_handler = null;
private BluetoothDevice device;
private BluetoothGattDescriptor descriptor;
private final IBinder binder = new LocalBinder();
public boolean isConnected() {
return connected;
}
private boolean connected = false;
// messages sent back to activity
public static final int GATT_CONNECTED = 1;
public static final int GATT_DISCONNECT = 2;
public static final int GATT_SERVICES_DISCOVERED = 3;
public static final int GATT_CHARACTERISTIC_READ = 4;
public static final int GATT_CHARACTERISTIC_WRITTEN = 5;
public static final int GATT_REMOTE_RSSI = 6;
public static final int MESSAGE = 7;
// message params
public static final String PARCEL_DESCRIPTOR_UUID = "DESCRIPTOR_UUID";
public static final String PARCEL_CHARACTERISTIC_UUID = "CHARACTERISTIC_UUID";
public static final String PARCEL_SERVICE_UUID = "SERVICE_UUID";
public static final String PARCEL_VALUE = "VALUE";
public static final String PARCEL_RSSI = "RSSI";
public static final String PARCEL_TEXT = "TEXT";
// service uuids
public static String IMMEDIATE_ALERT_SERVICE_UUID = "00001802-0000-1000-8000-00805F9B34FB";
public static String LINK_LOSS_SERVICE_UUID = "00001803-0000-1000-8000-00805F9B34FB";
public static String TX_POWER_SERVICE_UUID = "00001804-0000-1000-8000-00805F9B34FB";
public static String PROXIMITY_MONITORING_SERVICE_UUID = "3E099910-293F-11E4-93BD-AFD0FE6D1DFD";
// service characteristics
public static String ALERT_LEVEL_CHARACTERISTIC = "00002A06-0000-1000-8000-00805F9B34FB";
public static String CLIENT_PROXIMITY_CHARACTERISTIC = "3E099911-293F-11E4-93BD-AFD0FE6D1DFD";
public class LocalBinder extends Binder {
public BleAdapterService getService() {
return BleAdapterService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
// set activity the will receive the messages
public void setActivityHandler(Handler handler) {
activity_handler = handler;
}
private void sendConsoleMessage(String text) {
Message msg = Message.obtain(activity_handler, MESSAGE);
Bundle data = new Bundle();
data.putString(PARCEL_TEXT, text);
msg.setData(data);
msg.sendToTarget();
}
#Override
public void onCreate() {
if (bluetooth_manager == null) {
bluetooth_manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetooth_manager == null) {
return;
}
}
bluetooth_adapter = bluetooth_manager.getAdapter();
if (bluetooth_adapter == null) {
return;
}
}
// connect to the device
public boolean connect(final String address) {
if (bluetooth_adapter == null || address == null) {
sendConsoleMessage("connect: bluetooth_adapter=null");
return false;
}
device = bluetooth_adapter.getRemoteDevice(address);
if (device == null) {
sendConsoleMessage("connect: device=null");
return false;
}
bluetooth_gatt = device.connectGatt(this, false, gatt_callback);
return true;
}
// disconnect from device
public void disconnect() {
sendConsoleMessage("disconnecting");
if (bluetooth_adapter == null || bluetooth_gatt == null) {
sendConsoleMessage("disconnect: bluetooth_adapter|bluetooth_gatt null");
return;
}
if (bluetooth_gatt != null) {
bluetooth_gatt.disconnect();
}
}
public void readRemoteRssi() {
if (bluetooth_adapter == null || bluetooth_gatt == null) {
return;
}
bluetooth_gatt.readRemoteRssi();
}
public void discoverServices() {
if (bluetooth_adapter == null || bluetooth_gatt == null) {
return;
}
Log.d(Constants.TAG,"Discovering GATT services");
bluetooth_gatt.discoverServices();
}
public List<BluetoothGattService> getSupportedGattServices() {
if (bluetooth_gatt == null)
return null;
return bluetooth_gatt.getServices();
}
public boolean readCharacteristic(String serviceUuid,
String characteristicUuid) {
Log.d(Constants.TAG,"readCharacteristic:"+characteristicUuid+" of " +serviceUuid);
if (bluetooth_adapter == null || bluetooth_gatt == null) {
sendConsoleMessage("readCharacteristic: bluetooth_adapter|bluetooth_gatt null");
return false;
}
BluetoothGattService gattService = bluetooth_gatt
.getService(java.util.UUID.fromString(serviceUuid));
if (gattService == null) {
sendConsoleMessage("readCharacteristic: gattService null");
return false;
}
BluetoothGattCharacteristic gattChar = gattService
.getCharacteristic(java.util.UUID.fromString(characteristicUuid));
if (gattChar == null) {
sendConsoleMessage("readCharacteristic: gattChar null");
return false;
}
return bluetooth_gatt.readCharacteristic(gattChar);
}
public boolean writeCharacteristic(String serviceUuid,
String characteristicUuid, byte[] value) {
Log.d(Constants.TAG,"writeCharacteristic:"+characteristicUuid+" of " +serviceUuid);
if (bluetooth_adapter == null || bluetooth_gatt == null) {
sendConsoleMessage("writeCharacteristic: bluetooth_adapter|bluetooth_gatt null");
return false;
}
BluetoothGattService gattService = bluetooth_gatt
.getService(java.util.UUID.fromString(serviceUuid));
if (gattService == null) {
sendConsoleMessage("writeCharacteristic: gattService null");
return false;
}
BluetoothGattCharacteristic gattChar = gattService
.getCharacteristic(java.util.UUID.fromString(characteristicUuid));
if (gattChar == null) {
sendConsoleMessage("writeCharacteristic: gattChar null");
return false;
}
gattChar.setValue(value);
return bluetooth_gatt.writeCharacteristic(gattChar);
}
private final BluetoothGattCallback gatt_callback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
Log.d(Constants.TAG, "onConnectionStateChange: status=" + status);
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d(Constants.TAG, "onConnectionStateChange: CONNECTED");
connected = true;
Message msg = Message.obtain(activity_handler, GATT_CONNECTED);
msg.sendToTarget();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d(Constants.TAG, "onConnectionStateChange: DISCONNECTED");
Message msg = Message.obtain(activity_handler, GATT_DISCONNECT);
msg.sendToTarget();
if (bluetooth_gatt != null) {
Log.d(Constants.TAG,"Closing and destroying BluetoothGatt object");
connected = false;
bluetooth_gatt.close();
bluetooth_gatt = null;
}
}
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
sendConsoleMessage("RSSI read OK");
Bundle bundle = new Bundle();
bundle.putInt(PARCEL_RSSI, rssi);
Message msg = Message
.obtain(activity_handler, GATT_REMOTE_RSSI);
msg.setData(bundle);
msg.sendToTarget();
} else {
sendConsoleMessage("RSSI read err:"+status);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
sendConsoleMessage("Services Discovered");
Message msg = Message.obtain(activity_handler,
GATT_SERVICES_DISCOVERED);
msg.sendToTarget();
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Bundle bundle = new Bundle();
bundle.putString(PARCEL_CHARACTERISTIC_UUID, characteristic.getUuid()
.toString());
bundle.putString(PARCEL_SERVICE_UUID, characteristic.getService().getUuid().toString());
bundle.putByteArray(PARCEL_VALUE, characteristic.getValue());
Message msg = Message.obtain(activity_handler,
GATT_CHARACTERISTIC_READ);
msg.setData(bundle);
msg.sendToTarget();
} else {
Log.d(Constants.TAG, "failed to read characteristic:"+characteristic.getUuid().toString()+" of service "+characteristic.getService().getUuid().toString()+" : status="+status);
sendConsoleMessage("characteristic read err:"+status);
}
}
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
Log.d(Constants.TAG, "onCharacteristicWrite");
if (status == BluetoothGatt.GATT_SUCCESS) {
Bundle bundle = new Bundle();
bundle.putString(PARCEL_CHARACTERISTIC_UUID, characteristic.getUuid().toString());
bundle.putString(PARCEL_SERVICE_UUID, characteristic.getService().getUuid().toString());
bundle.putByteArray(PARCEL_VALUE, characteristic.getValue());
Message msg = Message.obtain(activity_handler, GATT_CHARACTERISTIC_WRITTEN);
msg.setData(bundle);
msg.sendToTarget();
} else {
sendConsoleMessage("characteristic write err:" + status);
}
}
};
}
I forgot to add the service in the Manifest as this:
<service
android:name=".bluetooth.BleAdapterService"
android:enabled="true" />
Related
I am building an app where I need BLE devices to connect with each other and send messages. My problem is when my android device connects to an iOS device, only the iOS devices receives the message that android is advertising. Android never recieves the message iOS is sending. After debugging and testing, I am certain this is a problem with android, not iOS because iOS devices send and receive messages between each other properly.
I am confused on what to fix with my android code in order to have it successfully receive messages from iOS.
public class mapActivity extends AppCompatActivity implements OnMapReadyCallback {
private final Set<Peer> nearbyPeers = new HashSet<>();
private static Map<String, String> times = new HashMap<>();
private int counter = 0;
private static final String TAG2 = "ClientActivity";
private static final int REQUEST_ENABLE_BT = 1;
private static final String docName = "docName";
private boolean mConnected;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private ScanCallback mScanCallback;
private BluetoothGatt mGatt;
public String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
public static final long SCAN_PERIOD = 5000;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
private BluetoothGattServer mGattServer;
private BluetoothGatt gatt;
private boolean mEchoInitialized;
private List<BluetoothDevice> mDevices;
private BluetoothManager mBluetoothManager;
private boolean mInitialized;
FirebaseFirestore db = FirebaseFirestore.getInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLogHandler = new Handler(Looper.getMainLooper());
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
#SuppressLint("HardwareIds")
String deviceInfo = "Device Info"
+ "\nName: " + mBluetoothAdapter.getName()
+ "\nAddress: " + mBluetoothAdapter.getAddress();
mHandler = new Handler();
mDevices = new ArrayList<>();
//End of ServerActivity
startScan();
}
#Override
protected void onResume() {
super.onResume();
//ClientActivity
// Check low energy support
//ServerActivity
// Check if bluetooth is enabled
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
// Request user to enable it
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
finish();
return;
}
// Check low energy support
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
// Get a newer device
System.out.println("No LE Support.");
finish();
return;
}
// Check advertising
if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) {
// Unable to run the server on this device, get a better device
System.out.println("No Advertising Support.");
finish();
return;
}
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
GattServerCallback gattServerCallback = new GattServerCallback();
//try {
if (gattServerCallback == null || this == null || mBluetoothManager == null) {
System.out.println("unable to print gatt server");
return;
}
mGattServer = mBluetoothManager.openGattServer(this, gattServerCallback);
//}
//catch (Exception e) {
//}
#SuppressLint("HardwareIds")
String deviceInfo = "Device Info" + "\nName: " + mBluetoothAdapter.getName() + "\nAddress: " + mBluetoothAdapter.getAddress();
setupServer();
startAdvertising();
//startScan();
}
#Override
protected void onPause() {
super.onPause();
stopAdvertising();
stopServer();
}
//ServerActivity Start Advertising
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startAdvertising() {
if (mBluetoothLeAdvertiser == null) {
return;
}
AdvertiseSettings settings = new AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setConnectable(true)
.setTimeout(0)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW)
.build();
ParcelUuid parcelUuid = ParcelUuid.fromString(covtraceUUID);
AdvertiseData data = new AdvertiseData.Builder().setIncludeDeviceName(false)
//.addServiceUuid(new ParcelUuid(serviceUUID));
.addServiceUuid(parcelUuid)
.addServiceData( parcelUuid, "d".getBytes(Charset.forName("UTF-8") ) )
.build();
mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
}
//ServerActivity stop advertising
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopAdvertising() {
if (mBluetoothLeAdvertiser != null) {
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
}
}
private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
System.out.println("Peripheral advertising started.");
}
#Override
public void onStartFailure(int errorCode) {
System.out.println("Peripheral advertising failed: " + errorCode);
}
};
//ServerActivity log
public void log1(String msg) {
Log.d(TAG, msg);
}
public void addDevice(BluetoothDevice device) {
System.out.println("Device added: " + device.getAddress());
mHandler.post(() -> mDevices.add(device));
}
public void removeDevice(BluetoothDevice device) {
System.out.println("Device removed: " + device.getAddress());
mHandler.post(() -> {
mDevices.remove(device);
});
}
private static boolean uuidMatches(String uuidString, String... matches) {
for (String match : matches) {
if (uuidString.equalsIgnoreCase(match)) {
return true;
}
}
return false;
}
private static boolean matchesServiceUuidString(String serviceIdString) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return uuidMatches(serviceIdString, covtraceUUID);
}
#Nullable
private static BluetoothGattService findService(List<BluetoothGattService> serviceList) {
for (BluetoothGattService service : serviceList) {
String serviceIdString = service.getUuid()
.toString();
if (matchesServiceUuidString(serviceIdString)) {
return service;
}
}
return null;
}
private static boolean characteristicMatches(BluetoothGattCharacteristic characteristic, String uuidString) {
if (characteristic == null) {
return false;
}
UUID uuid = characteristic.getUuid();
return uuidMatches(uuid.toString(), uuidString);
}
#Nullable
private static BluetoothGattCharacteristic findCharacteristic(BluetoothGatt bluetoothGatt, String uuidString) {
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = findService(serviceList);
if (service == null) {
System.out.println("our service is null!!!!!!!");
return null;
}
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
if (characteristicMatches(characteristic, uuidString)) {
return characteristic;
}
}
return null;
}
public static byte[] bytesFromString(String string) {
byte[] stringBytes = new byte[0];
try {
stringBytes = string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Failed to convert message string to byte array");
}
return stringBytes;
}
#Nullable
public static BluetoothGattCharacteristic findEchoCharacteristic(BluetoothGatt bluetoothGatt) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return findCharacteristic(bluetoothGatt, covtraceUUID);
}
//ServerActivity send message
private void sendMessage() {
if (!mConnected || !mEchoInitialized) {
return;
}
BluetoothGattCharacteristic characteristic = findEchoCharacteristic(mGatt);
if (characteristic == null) {
logError("Unable to find echo characteristic.");
disconnectGattServer();
return;
}
String message = String.valueOf(P2PKit.getMyPeerId());
byte[] messageBytes = bytesFromString(message);
if (messageBytes.length == 0) {
logError("Unable to convert message to bytes");
return;
}
characteristic.setValue(messageBytes);
boolean success = mGatt.writeCharacteristic(characteristic);
if (success) {
log("Wrote: " + byteArrayInHexFormat(messageBytes));
} else {
logError("Failed to write data");
}
}
//ServerActivity characteristic changed
private class CharacteristicChanged extends BluetoothGattCallback {
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] messageBytes = characteristic.getValue();
String messageString = null;
try {
messageString = new String(messageBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.d(TAG, "Unable to convert message bytes to string");
}
Log.d(messageString, "Received message: ");
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
return;
}
BluetoothGattService service = gatt.getService(UUID.fromString(covtraceUUID));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(covtraceUUID));
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
mInitialized = gatt.setCharacteristicNotification(characteristic, true);
}
}
public static boolean requiresResponse(BluetoothGattCharacteristic characteristic) {
return (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
}
public void sendResponse(BluetoothDevice device, int requestId, int status, int offset, byte[] value) {
mHandler.post(() -> mGattServer.sendResponse(device, requestId, status, 0, null));
}
public static byte[] reverse(byte[] value) {
int length = value.length;
byte[] reversed = new byte[length];
for (int i = 0; i < length; i++) {
reversed[i] = value[length - (i + 1)];
}
return reversed;
}
private static String byteToHex(byte b) {
char char1 = Character.forDigit((b & 0xF0) >> 4, 16);
char char2 = Character.forDigit((b & 0x0F), 16);
return String.format("0x%1$s%2$s", char1, char2);
}
public static String byteArrayInHexFormat(byte[] byteArray) {
if (byteArray == null) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("{ ");
for (int i = 0; i < byteArray.length; i++) {
if (i > 0) {
stringBuilder.append(", ");
}
String hexString = byteToHex(byteArray[i]);
stringBuilder.append(hexString);
}
stringBuilder.append(" }");
return stringBuilder.toString();
}
public static boolean requiresConfirmation(BluetoothGattCharacteristic characteristic) {
return (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE;
}
private void notifyCharacteristic(byte[] value, UUID uuid) {
mHandler.post(() -> {
BluetoothGattService service = mGattServer.getService(UUID.fromString(covtraceUUID));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid);
log("Notifying characteristic " + characteristic.getUuid().toString()
+ ", new value: " + byteArrayInHexFormat(value));
characteristic.setValue(value);
boolean confirm = requiresConfirmation(characteristic);
for(BluetoothDevice device : mDevices) {
mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
}
});
}
public void notifyCharacteristicEcho(byte[] value) {
notifyCharacteristic(value, UUID.fromString(covtraceUUID));
}
private void sendReverseMessage(byte[] message) {
mHandler.post(() -> {
// Reverse message to differentiate original message & response
byte[] response = reverse(message);
log("Sending: " + byteArrayInHexFormat(response));
notifyCharacteristicEcho(response);
});
}
//ServerActivity gattservercallback
private class GattServerCallback extends BluetoothGattServerCallback {
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
addDevice(device);
connectDevice(device);
System.out.println("preparing to send msg 1");
sendMessage();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
removeDevice(device);
}
}
// The Gatt will reject Characteristic Read requests that do not have the permission set,
// so there is no need to check inside the callback
#Override
public void onCharacteristicReadRequest(BluetoothDevice device,
int requestId,
int offset,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
log("onCharacteristicReadRequest "
+ characteristic.getUuid().toString());
if (requiresResponse(characteristic)) {
// Unknown read characteristic requiring response, send failure
sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
}
System.out.println("preparing to send msg 2");
sendMessage();
// Not one of our characteristics or has NO_RESPONSE property set
}
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device,
int requestId,
BluetoothGattCharacteristic characteristic,
boolean preparedWrite,
boolean responseNeeded,
int offset,
byte[] value) {
super.onCharacteristicWriteRequest(device,
requestId,
characteristic,
preparedWrite,
responseNeeded,
offset,
value);
if (UUID.fromString(covtraceUUID).equals(characteristic.getUuid())) {
sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
sendReverseMessage(value);
}
System.out.println("preparing to send msg 3");
sendMessage();
}
}
//ServerActivity set up server
private void setupServer() {
BluetoothGattService service = new BluetoothGattService(UUID.fromString(covtraceUUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
mGattServer.addService(service);
}
//ServerActivity stop server
private void stopServer() {
if (mGattServer != null) {
mGattServer.close();
}
}
public void log(String msg) {
Log.d(TAG, msg);
mLogHandler.post(() -> {
Log.i(msg, msg + "\n");
});
}
public void logError(String msg) {
log("Error: " + msg);
}
//ClientActivity Scanning
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startScan() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!hasPermissions() || mScanning) {
return;
}
}
disconnectGattServer();
mScanResults = new HashMap<>();
mScanCallback = new BtleScanCallback(mScanResults);
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Note: Filtering does not work the same (or at all) on most devices. It also is unable to
// search for a mask or anything less than a full UUID.
// Unless the full UUID of the server is known, manual filtering may be necessary.
// For example, when looking for a brand of device that contains a char sequence in the UUID
ScanFilter scanFilter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(covtraceUUID))
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add(scanFilter);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
mHandler = new Handler();
//mHandler.postDelayed(this::stopScan, SCAN_PERIOD);
mScanning = true;
System.out.println("Started scanning.");
}
#RequiresApi(api = Build.VERSION_CODES.M)
private boolean hasPermissions() {
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
requestBluetoothEnable();
return false;
}
return true;
}
private void requestBluetoothEnable() {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
log("Requested user enables Bluetooth. Try starting the scan again.");
}
private void connectDevice(BluetoothDevice device) {
log("Connecting to " + device.getAddress());
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = device.connectGatt(this, false, gattClientCallback);
}
//ClientActivity Stop scan
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopScan() {
if (mScanning && mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mBluetoothLeScanner != null) {
mBluetoothLeScanner.stopScan(mScanCallback);
scanComplete();
}
mScanCallback = null;
mScanning = false;
mHandler = null;
System.out.println("Stopped scanning.");
}
//ClientActivity scan Complete
private void scanComplete() {
if (mScanResults.isEmpty()) {
return;
}
for (String deviceAddress : mScanResults.keySet()) {
BluetoothDevice device = mScanResults.get(deviceAddress);
GattServerViewModel viewModel = new GattServerViewModel(device);
}
}
//Client Activity set connected
public void setConnected(boolean connected) {
mConnected = connected;
}
public void initializeEcho() {
mEchoInitialized = true;
}
//ClientActivity disconnect Gatt server
public void disconnectGattServer() {
System.out.println("Closing Gatt connection");
mConnected = false;
mEchoInitialized = false;
if (mGatt != null) {
mGatt.disconnect();
mGatt.close();
}
}
private static boolean matchesCharacteristicUuidString(String characteristicIdString) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return uuidMatches(characteristicIdString, covtraceUUID);
}
private static boolean isMatchingCharacteristic(BluetoothGattCharacteristic characteristic) {
if (characteristic == null) {
return false;
}
UUID uuid = characteristic.getUuid();
return matchesCharacteristicUuidString(uuid.toString());
}
public static List<BluetoothGattCharacteristic> findCharacteristics(BluetoothGatt bluetoothGatt) {
List<BluetoothGattCharacteristic> matchingCharacteristics = new ArrayList<>();
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = findService(serviceList);
if (service == null) {
System.out.println("cannot find charac");
return matchingCharacteristics;
}
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
if (isMatchingCharacteristic(characteristic)) {
matchingCharacteristics.add(characteristic);
}
}
return matchingCharacteristics;
}
//Client Activity callback
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class BtleScanCallback extends ScanCallback {
private Map<String, BluetoothDevice> mScanResults;
BtleScanCallback(Map<String, BluetoothDevice> scanResults) {
mScanResults = scanResults;
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
addScanResult(result);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult result : results) {
addScanResult(result);
}
}
#Override
public void onScanFailed(int errorCode) {
logError("BLE Scan Failed with code " + errorCode);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void addScanResult(ScanResult result) {
BluetoothDevice device = result.getDevice();
String deviceAddress = device.getAddress();
mScanResults.put(deviceAddress, device);
}
}
#Nullable
public static String stringFromBytes(byte[] bytes) {
String byteString = null;
try {
byteString = new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to convert message bytes to string");
}
return byteString;
}
public static boolean isEchoCharacteristic(BluetoothGattCharacteristic characteristic) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return characteristicMatches(characteristic, covtraceUUID );
}
//Gatt Client Callback
private class GattClientCallback extends BluetoothGattCallback {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
System.out.println("onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
logError("Connection Gatt failure status " + status);
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
logError("Connection not GATT sucess status " + status);
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
System.out.println("Connected to device " + gatt.getDevice().getAddress());
mConnected = true;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
System.out.println("Disconnected from device");
disconnectGattServer();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
log("Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics = findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
logError("Unable to find characteristics.");
return;
}
log("Initializing: setting write type and enabling notification");
for (BluetoothGattCharacteristic characteristic : matchingCharacteristics) {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
enableCharacteristicNotification(gatt, characteristic);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
log("Characteristic written successfully");
} else {
logError("Characteristic write unsuccessful, status: " + status);
disconnectGattServer();
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
log("Characteristic read successfully");
readCharacteristic(characteristic);
} else {
logError("Characteristic read unsuccessful, status: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
log("Characteristic changed, " + characteristic.getUuid().toString());
readCharacteristic(characteristic);
}
private void enableCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
boolean characteristicWriteSuccess = gatt.setCharacteristicNotification(characteristic, true);
if (characteristicWriteSuccess) {
log("Characteristic notification set successfully for " + characteristic.getUuid().toString());
if (isEchoCharacteristic(characteristic)) {
System.out.println("enters isechocharac... ab to init");
initializeEcho();
System.out.println("preparing to send msg 4");
sendMessage();
}
} else {
logError("Characteristic notification set failure for " + characteristic.getUuid().toString());
}
}
private void readCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] messageBytes = characteristic.getValue();
log("Read: " + byteArrayInHexFormat(messageBytes));
String message = stringFromBytes(messageBytes);
if (message == null) {
logError("Unable to convert bytes to string");
return;
}
log("Received message: " + message);
}
}
#Override
public void onStart() {
super.onStart();
}
I'm trying to connect to random Bluetooth device that match a certain characteristic. I just want to print the incoming messages from the bluetooth device.
I've been trying for the past few days to try and connect to some random bluetooth device that matches a characteristic so that I'll be able to just print the messages from the bluetooth device.
public class main extends AppCompatActivity {
private List Service_UUIDs;
private List Charac_UUIDS;
private List Descriptor_UUIDs;
public static final UUID descriptor = UUID.fromString("863930fc-947c-421b-
9170-9969ea6ad610");
private BluetoothAdapter bluetoothAdapter = null;
private BluetoothLeScanner bluetoothLeScanner;
private ScanCallback scanCallback;
private TextView messageText;
private Handler handler;
private static final int SCAN_TIME = 15000;
private int connectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTED = 2;
private boolean isConnected;
private boolean isScanning;
private BluetoothLeScanner myScanner;
private BluetoothGatt bluetoothGatt;
private String connected = "";
public List<BluetoothGattService> myServices;
private ScanCallback myScanCallBack;
private BluetoothDevice myDevice;
private HashMap<String, BluetoothDevice> myScanResults;
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 static final int REQUEST_ENABLE_BT = 10;
private void unpairDevice(BluetoothDevice device) {
try {
Method m = device.getClass().getMethod("removeBond", (Class[])
null);
m.invoke(device, (Object[]) null);
Log.d("unpairDevice", Integer.toString(device.getBondState()));
}
catch (Exception e) { Log.e("unpairDevice", e.getMessage()); }
}
private void makeToast(String message) {
//creates pop-ups in UI of the message
Context context = getApplicationContext();
CharSequence text = message;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BluetoothManager bluetoothManager = (BluetoothManager)
getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
if(!bluetoothManager.getAdapter().isEnabled()){
Intent btEnable = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(btEnable, REQUEST_ENABLE_BT);
}
messageText = findViewById(R.id.atm_msg);
findViewById(R.id.scan_button).setOnClickListener(new handleScan());
}
class handleScan implements View.OnClickListener{
public void onClick(View view){
startScan();
}
}
private void startScan() {
List<ScanFilter> filters = new ArrayList<>();
ScanFilter scanFilter = new ScanFilter.Builder()
.setServiceUuid(new ParcelUuid(descriptor))
.build();
filters.add(scanFilter);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
myScanResults = new HashMap<>();
myScanCallBack = new BtleScanCallback(myScanResults);
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(myScanCallBack);
isScanning = true;
new Handler().postDelayed(this::stopScan, SCAN_TIME);
}
private void stopScan(){
if(isScanning && bluetoothAdapter != null
&& bluetoothAdapter.isEnabled()
&& bluetoothLeScanner != null){
bluetoothLeScanner.stopScan(myScanCallBack);
scanComplete();
}
myScanCallBack = null;
isScanning = false;
handler = null;
}
private void scanComplete(){
if (myScanResults.isEmpty()){
return;
}
for(BluetoothDevice device: myScanResults.values()){
connectDevice(device);
}
}
protected class BtleScanCallback extends ScanCallback {
private HashMap<String, BluetoothDevice> myScanResults;
BtleScanCallback(HashMap<String, BluetoothDevice> scanResults) {
myScanResults = scanResults;
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
addScanResult(result);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult result : results) {
addScanResult(result);
}
}
#Override
public void onScanFailed(int errorCode) {
makeToast("BLE Scan Failed with code " + errorCode);
}
private void addScanResult(ScanResult result) {
myDevice = result.getDevice();
String deviceAddress = myDevice.getAddress();
myScanResults.put(deviceAddress, myDevice);
}
}
private void connectDevice(BluetoothDevice device) {
bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
}
private final BluetoothGattCallback bluetoothGattCallback = new
BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int
newState) {
super.onConnectionStateChange(gatt, status, newState);
if (status == gatt.GATT_FAILURE){
Log.d("BLE_Assistance", "-----> status: " + gatt.GATT_FAILURE);
disconnectGattServer();
return;
}
if (status == 133){
bluetoothAdapter.disable();
bluetoothAdapter.enable();
Log.d("OCSC: ", "133 GATT_ERROR OCCURRED");
}
if (newState == gatt.STATE_CONNECTED){
Log.d("BLE_Assistance", "-----> state: " +
gatt.STATE_CONNECTED);
connectionState = gatt.STATE_CONNECTED;
isConnected = true;
return;
}
else if (status != gatt.GATT_SUCCESS){
Log.d("BLE_Assistance", "-----> status: could not connect");
disconnectGattServer();
return;
}
else if (newState == gatt.STATE_DISCONNECTED){
Log.d("BLE_Assistance", "status: " + gatt.STATE_DISCONNECTED);
disconnectGattServer();
}
}
public void disconnectGattServer(){
isConnected = false;
connected = "";
if (bluetoothLeScanner != null && scanCallback != null){
bluetoothLeScanner.flushPendingScanResults(scanCallback);
}
if (!myScanResults.isEmpty()){
myScanResults.clear();
}
try {
if (myServices.isEmpty()){
Log.d("Services", "Empty");
}
else{
myServices.clear();
}
} catch (NullPointerException nullPointerException){
Log.d("Services", "" + nullPointerException);
}
bluetoothAdapter.cancelDiscovery();
if(bluetoothGatt != null){
bluetoothGatt.abortReliableWrite();
bluetoothGatt.disconnect();
bluetoothGatt.close();
bluetoothGatt = null;
Log.d("disconnect server", ": Disconnected GATT Server");
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
byte[] msg_bytes = characteristic.getValue();
try {
String message = new String(msg_bytes, 0, msg_bytes.length,
"utf-8");
Log.d("onCharacteristicRead", message);
new Handler(Looper.getMainLooper()).postDelayed(() -> {
makeToast("onCharacteristicRead: " + message);
messageText.append("\nonCharacteristicRead: " + message);
}, 1000);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status){
super.onServicesDiscovered(gatt,status);
Service_UUIDs = new ArrayList();
Charac_UUIDS = new ArrayList();
Descriptor_UUIDs = new ArrayList();
if(status != gatt.GATT_SUCCESS){
return;
}else{
myServices = gatt.getServices();
for (BluetoothGattService service : myServices) {
for (BluetoothGattCharacteristic charac : service.getCharacteristics()) {
if (charac.getUuid().toString().contains("863930fc")) {
Service_UUIDs.add(charac.getService().getUuid().toString());
Charac_UUIDS.add(charac.getUuid().toString());
Descriptor_UUIDs.add(descriptor);
BluetoothGattDescriptor desc = charac.getDescriptor(descriptor);
gatt.setCharacteristicNotification(charac, true);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
}
}
}
Log.d("BLE_Assistance", "------ UUID Lists: " + Service_UUIDs + Charac_UUIDS + Descriptor_UUIDs);
}
}
};
}
I am not completely sure, I am also struggling with this kind of project right now and I am quite new to programming on Android. But I spotted a small mistake in your startScan and stopScan codes
bluetoothLeScanner.startScan(myScanCallBack);
Should be
bluetoothLeScanner.startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)
with your scan filters and settings.
When you only send 'myScanCallback' to your 'bluetoothLeScanner.startScan', you're sending only default parameters with no filters.
https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.bluetooth.le.ScanCallback)
This means that you're searching for every device, and not specifically the one you want.
For testing while powerdraw isn't an issue, you can also set your ScanSettings to LOW_LATENCY (LOW_POWER is more intuitive to use with BLE but not a requirement. You can switch it later when you want more battery life while scanning).
I hope it helps you
I keep getting an an error when trying to call WowZa GoCoder SDK's PlayerActivity and I am unable to understand the cause. The error appears when mStreamPlayerView.play(mStreamPlayerConfig, statusCallback) is called. Would really appreciate help on where i am going wrong
vodFragment.java
public class vodFragment extends Fragment {
private int mColumnCount = 1;
ListView videoView;
ArrayList <Vidoes> videoList;
private static String value;
String videoName;
String url = "http://192.168.43.149/twende/channelVOD.php";
public vodFragment() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (getActivity().getActionBar() != null) {
getActivity().getActionBar().setTitle(value);
}
View view = inflater.inflate(R.layout.fragment_vod_list, container, false);
videoView = (ListView) view.findViewById(R.id.listView);
videoList = new ArrayList<Vidoes>();
JSONObject channelInfo = new JSONObject();
try {
channelInfo.put("channelName", value);
channelInfo.put("channelOwner", "dan");
postJSONObject(url,channelInfo);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return view;
}
public static void setChannel(String channel){
value = channel;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
}
public void postJSONObject(final String myurl, final JSONObject parameters) {
class postJSONObject extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
loadIntoVodView(s);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected String doInBackground(Void... voids) {
HttpURLConnection conn = null;
try {
StringBuffer response = null;
URL url = new URL(myurl);
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setRequestMethod("POST");
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
writer.write(parameters.toString());
writer.close();
out.close();
int responseCode = conn.getResponseCode();
System.out.println("responseCode" + responseCode);
switch (responseCode) {
case 200:
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (conn != null) {
try {
conn.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
return null;
}
}
postJSONObject postJSONObject = new postJSONObject();
postJSONObject.execute();
}
private void loadIntoVodView(String json) throws JSONException {
JSONArray jsonArray = new JSONArray(json);
final String[] videos = new String[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject obj = jsonArray.getJSONObject(i);
videos[i] = removeExtension(obj.getString("title"));
Vidoes vidoe = new Vidoes();
vidoe.setTitle(videos[i]);
videoList.add(vidoe);
}
VideoListAdapter adapter = new VideoListAdapter(getActivity(), R.layout.vodparsedata, videoList);
videoView.setAdapter(adapter);
videoView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
videoName = Arrays.asList(videos).get(position);
Intent intent = new Intent(getActivity(), PlayerActivity.class);
String message = videoName+".mp4";
intent.putExtra("videoName", message);
startActivity(intent);
System.out.println("arr: " + Arrays.asList(videos).get(position));
}
});
}
public static String removeExtension(String fileName) {
if (fileName.indexOf(".") > 0) {
return fileName.substring(0, fileName.lastIndexOf("."));
} else {
return fileName;
}
}
}
PlayerActivity.java
public class PlayerActivity extends GoCoderSDKActivityBase {
final private static String TAG = PlayerActivity.class.getSimpleName();
String videoName;
private WOWZPlayerView mStreamPlayerView = null;
private WOWZPlayerConfig mStreamPlayerConfig = new WOWZPlayerConfig();
private MultiStateButton mBtnPlayStream = null;
private MultiStateButton mBtnSettings = null;
private MultiStateButton mBtnMic = null;
private MultiStateButton mBtnScale = null;
private SeekBar mSeekVolume = null;
private ProgressDialog mBufferingDialog = null;
private StatusView mStatusView = null;
private TextView mHelp = null;
private TimerView mTimerView = null;
private ImageButton mStreamMetadata = null;
private boolean mUseHLSPlayback = false;
private WOWZPlayerView.PacketThresholdChangeListener packetChangeListener = null;
private VolumeChangeObserver mVolumeSettingChangeObserver = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stream_player);
mRequiredPermissions = new String[]{};
if (savedInstanceState == null) {
Bundle extras = getIntent().getExtras();
if(extras == null) {
videoName= null;
} else {
videoName= extras.getString("videoName");
}
} else {
videoName= (String) savedInstanceState.getSerializable("videoName");
}
System.out.print(videoName);
mStreamPlayerConfig.setIsPlayback(true);
mStreamPlayerConfig.setHostAddress("192.168.43.149");
mStreamPlayerConfig.setApplicationName("Dark Souls 2 Channel");
mStreamPlayerConfig.setStreamName(videoName);
mStreamPlayerConfig.setPortNumber(1935);
mStreamPlayerView = (WOWZPlayerView) findViewById(R.id.vwStreamPlayer);
mBtnPlayStream = (MultiStateButton) findViewById(R.id.ic_play_stream);
mBtnSettings = (MultiStateButton) findViewById(R.id.ic_settings);
mBtnMic = (MultiStateButton) findViewById(R.id.ic_mic);
mBtnScale = (MultiStateButton) findViewById(R.id.ic_scale);
mTimerView = (TimerView) findViewById(R.id.txtTimer);
mStatusView = (StatusView) findViewById(R.id.statusView);
mStreamMetadata = (ImageButton) findViewById(R.id.imgBtnStreamInfo);
mHelp = (TextView) findViewById(R.id.streamPlayerHelp);
mSeekVolume = (SeekBar) findViewById(R.id.sb_volume);
WOWZStatusCallback statusCallback = new StatusCallback();
mStreamPlayerView.play(mStreamPlayerConfig, statusCallback);
mTimerView.setVisibility(View.GONE);
mStreamPlayerView.play(mStreamPlayerConfig, statusCallback);
if (sGoCoderSDK != null) {
/*
Packet change listener setup
*/
final PlayerActivity activity = this;
packetChangeListener = new WOWZPlayerView.PacketThresholdChangeListener() {
#Override
public void packetsBelowMinimumThreshold(int packetCount) {
WOWZLog.debug("Packets have fallen below threshold "+packetCount+"... ");
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Packets have fallen below threshold ... ", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void packetsAboveMinimumThreshold(int packetCount) {
WOWZLog.debug("Packets have risen above threshold "+packetCount+" ... ");
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Packets have risen above threshold ... ", Toast.LENGTH_SHORT).show();
}
});
}
};
mStreamPlayerView.setShowAllNotificationsWhenBelowThreshold(false);
mStreamPlayerView.setMinimumPacketThreshold(20);
mStreamPlayerView.registerPacketThresholdListener(packetChangeListener);
///// End packet change notification listener
mTimerView.setTimerProvider(new TimerView.TimerProvider() {
#Override
public long getTimecode() {
return mStreamPlayerView.getCurrentTime();
}
#Override
public long getDuration() {
return mStreamPlayerView.getDuration();
}
});
mSeekVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mStreamPlayerView != null && mStreamPlayerView.isPlaying()) {
mStreamPlayerView.setVolume(progress);
}
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// listen for volume changes from device buttons, etc.
mVolumeSettingChangeObserver = new VolumeChangeObserver(this, new Handler());
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mVolumeSettingChangeObserver);
mVolumeSettingChangeObserver.setVolumeChangeListener(new VolumeChangeObserver.VolumeChangeListener() {
#Override
public void onVolumeChanged(int previousLevel, int currentLevel) {
if (mSeekVolume != null)
mSeekVolume.setProgress(currentLevel);
if (mStreamPlayerView != null && mStreamPlayerView.isPlaying()) {
mStreamPlayerView.setVolume(currentLevel);
}
}
});
mBtnScale.setState(mStreamPlayerView.getScaleMode() == WOWZMediaConfig.FILL_VIEW);
// The streaming player configuration properties
mStreamPlayerConfig = new WOWZPlayerConfig();
mBufferingDialog = new ProgressDialog(this);
mBufferingDialog.setTitle(R.string.status_buffering);
mBufferingDialog.setMessage(getResources().getString(R.string.msg_please_wait));
mBufferingDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getResources().getString(R.string.button_cancel), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
cancelBuffering(dialogInterface);
}
});
// testing player data event handler.
mStreamPlayerView.registerDataEventListener("onMetaData", new WOWZDataEvent.EventListener(){
#Override
public WOWZDataMap onWZDataEvent(String eventName, WOWZDataMap eventParams) {
String meta = "";
if(eventParams!=null)
meta = eventParams.toString();
WOWZLog.debug("onWZDataEvent -> eventName "+eventName+" = "+meta);
return null;
}
});
// testing player data event handler.
mStreamPlayerView.registerDataEventListener("onStatus", new WOWZDataEvent.EventListener(){
#Override
public WOWZDataMap onWZDataEvent(String eventName, WOWZDataMap eventParams) {
if(eventParams!=null)
WOWZLog.debug("onWZDataEvent -> eventName "+eventName+" = "+eventParams.toString());
return null;
}
});
// testing player data event handler.
mStreamPlayerView.registerDataEventListener("onTextData", new WOWZDataEvent.EventListener(){
#Override
public WOWZDataMap onWZDataEvent(String eventName, WOWZDataMap eventParams) {
if(eventParams!=null)
WOWZLog.debug("onWZDataEvent -> "+eventName+" = "+eventParams.get("text"));
return null;
}
});
} else {
mHelp.setVisibility(View.GONE);
mStatusView.setErrorMessage(WowzaGoCoder.getLastError().getErrorDescription());
}
}
#Override
protected void onDestroy() {
if (mVolumeSettingChangeObserver != null)
getApplicationContext().getContentResolver().unregisterContentObserver(mVolumeSettingChangeObserver);
super.onDestroy();
}
/**
* Android Activity class methods
*/
#Override
protected void onResume() {
super.onResume();
syncUIControlState();
}
#Override
protected void onPause() {
if (mStreamPlayerView != null && mStreamPlayerView.isPlaying()) {
mStreamPlayerView.stop();
// Wait for the streaming player to disconnect and shutdown...
mStreamPlayerView.getCurrentStatus().waitForState(WOWZState.IDLE);
}
super.onPause();
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
public boolean isPlayerConfigReady()
{
return false;
}
/*
Click handler for network pausing
*/
public void onPauseNetwork(View v)
{
Button btn = (Button)findViewById(R.id.pause_network);
if(btn.getText().toString().trim().equalsIgnoreCase("pause network")) {
WOWZLog.info("Pausing network...");
btn.setText("Unpause Network");
mStreamPlayerView.pauseNetworkStack();
}
else{
WOWZLog.info("Unpausing network... btn.getText(): "+btn.getText());
btn.setText("Pause Network");
mStreamPlayerView.unpauseNetworkStack();
}
}
/**
* Click handler for the playback button
*/
public void onTogglePlayStream(View v) {
if (mStreamPlayerView.isPlaying()) {
mStreamPlayerView.stop();
} else if (mStreamPlayerView.isReadyToPlay()) {
if(!this.isNetworkAvailable()){
displayErrorDialog("No internet connection, please try again later.");
return;
}
// if(!this.isPlayerConfigReady()){
// displayErrorDialog("Please be sure to include a host, stream, and application to playback a stream.");
// return;
// }
mHelp.setVisibility(View.GONE);
WOWZStreamingError configValidationError = mStreamPlayerConfig.validateForPlayback();
if (configValidationError != null) {
mStatusView.setErrorMessage(configValidationError.getErrorDescription());
} else {
// Set the detail level for network logging output
mStreamPlayerView.setLogLevel(mWZNetworkLogLevel);
// Set the player's pre-buffer duration as stored in the app prefs
float preBufferDuration = GoCoderSDKPrefs.getPreBufferDuration(PreferenceManager.getDefaultSharedPreferences(this));
mStreamPlayerConfig.setPreRollBufferDuration(preBufferDuration);
// Start playback of the live stream
mStreamPlayerView.play(mStreamPlayerConfig, this);
}
}
}
/**
* WOWZStatusCallback interface methods
*/
#Override
public synchronized void onWZStatus(WOWZStatus status) {
final WOWZStatus playerStatus = new WOWZStatus(status);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
WOWZStatus status = new WOWZStatus(playerStatus.getState());
switch(playerStatus.getState()) {
case WOWZPlayerView.STATE_PLAYING:
// Keep the screen on while we are playing back the stream
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (mStreamPlayerConfig.getPreRollBufferDuration() == 0f) {
mTimerView.startTimer();
}
// Since we have successfully opened up the server connection, store the connection info for auto complete
GoCoderSDKPrefs.storeHostConfig(PreferenceManager.getDefaultSharedPreferences(PlayerActivity.this), mStreamPlayerConfig);
// Log the stream metadata
WOWZLog.debug(TAG, "Stream metadata:\n" + mStreamPlayerView.getMetadata());
break;
case WOWZPlayerView.STATE_READY_TO_PLAY:
// Clear the "keep screen on" flag
WOWZLog.debug(TAG, "STATE_READY_TO_PLAY player activity status!");
if(playerStatus.getLastError()!=null)
displayErrorDialog(playerStatus.getLastError());
playerStatus.clearLastError();
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mTimerView.stopTimer();
break;
case WOWZPlayerView.STATE_PREBUFFERING_STARTED:
WOWZLog.debug(TAG, "Dialog for buffering should show...");
showBuffering();
break;
case WOWZPlayerView.STATE_PREBUFFERING_ENDED:
WOWZLog.debug(TAG, "Dialog for buffering should stop...");
hideBuffering();
// Make sure player wasn't signaled to shutdown
if (mStreamPlayerView.isPlaying()) {
mTimerView.startTimer();
}
break;
default:
break;
}
syncUIControlState();
}
});
}
#Override
public synchronized void onWZError(final WOWZStatus playerStatus) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
displayErrorDialog(playerStatus.getLastError());
syncUIControlState();
}
});
}
public void onToggleMute(View v) {
mBtnMic.toggleState();
if (mStreamPlayerView != null)
mStreamPlayerView.mute(!mBtnMic.isOn());
mSeekVolume.setEnabled(mBtnMic.isOn());
}
public void onToggleScaleMode(View v) {
int newScaleMode = mStreamPlayerView.getScaleMode() == WOWZMediaConfig.RESIZE_TO_ASPECT ? WOWZMediaConfig.FILL_VIEW : WOWZMediaConfig.RESIZE_TO_ASPECT;
mBtnScale.setState(newScaleMode == WOWZMediaConfig.FILL_VIEW);
mStreamPlayerView.setScaleMode(newScaleMode);
}
public void onStreamMetadata(View v) {
WOWZDataMap streamMetadata = mStreamPlayerView.getMetadata();
WOWZDataMap streamStats = mStreamPlayerView.getStreamStats();
// WOWZDataMap streamConfig = mStreamPlayerView.getStreamConfig().toDataMap();
WOWZDataMap streamConfig = new WOWZDataMap();
WOWZDataMap streamInfo = new WOWZDataMap();
streamInfo.put("- Stream Statistics -", streamStats);
streamInfo.put("- Stream Metadata -", streamMetadata);
//streamInfo.put("- Stream Configuration -", streamConfig);
DataTableFragment dataTableFragment = DataTableFragment.newInstance("Stream Information", streamInfo, false, false);
getFragmentManager().beginTransaction()
.add(android.R.id.content, dataTableFragment)
.addToBackStack("metadata_fragment")
.commit();
}
public void onSettings(View v) {
// Display the prefs fragment
GoCoderSDKPrefs.PrefsFragment prefsFragment = new GoCoderSDKPrefs.PrefsFragment();
prefsFragment.setFixedSource(true);
prefsFragment.setForPlayback(true);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, prefsFragment)
.addToBackStack(null)
.commit();
}
private void syncUIControlState() {
boolean disableControls = (!(mStreamPlayerView.isReadyToPlay() || mStreamPlayerView.isPlaying()) || sGoCoderSDK == null);
if (disableControls) {
mBtnPlayStream.setEnabled(false);
mBtnSettings.setEnabled(false);
mSeekVolume.setEnabled(false);
mBtnScale.setEnabled(false);
mBtnMic.setEnabled(false);
mStreamMetadata.setEnabled(false);
} else {
mBtnPlayStream.setState(mStreamPlayerView.isPlaying());
mBtnPlayStream.setEnabled(true);
if (mStreamPlayerConfig.isAudioEnabled()) {
mBtnMic.setVisibility(View.VISIBLE);
mBtnMic.setEnabled(true);
mSeekVolume.setVisibility(View.VISIBLE);
mSeekVolume.setEnabled(mBtnMic.isOn());
mSeekVolume.setProgress(mStreamPlayerView.getVolume());
} else {
mSeekVolume.setVisibility(View.GONE);
mBtnMic.setVisibility(View.GONE);
}
mBtnScale.setVisibility(View.VISIBLE);
mBtnScale.setVisibility(mStreamPlayerView.isPlaying() && mStreamPlayerConfig.isVideoEnabled() ? View.VISIBLE : View.GONE);
mBtnScale.setEnabled(mStreamPlayerView.isPlaying() && mStreamPlayerConfig.isVideoEnabled());
mBtnSettings.setEnabled(!mStreamPlayerView.isPlaying());
mBtnSettings.setVisibility(mStreamPlayerView.isPlaying() ? View.GONE : View.VISIBLE);
mStreamMetadata.setEnabled(mStreamPlayerView.isPlaying());
mStreamMetadata.setVisibility(mStreamPlayerView.isPlaying() ? View.VISIBLE : View.GONE);
}
}
private void showBuffering() {
try {
if (mBufferingDialog == null) return;
mBufferingDialog.show();
}
catch(Exception ex){}
}
private void cancelBuffering(DialogInterface dialogInterface) {
if(mStreamPlayerConfig.getHLSBackupURL()!=null || mStreamPlayerConfig.isHLSEnabled()){
mStreamPlayerView.stop(true);
}
else if (mStreamPlayerView != null && mStreamPlayerView.isPlaying()) {
mStreamPlayerView.stop(true);
}
}
private void hideBuffering() {
if (mBufferingDialog.isShowing())
mBufferingDialog.dismiss();
}
#Override
public void syncPreferences() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mWZNetworkLogLevel = Integer.valueOf(prefs.getString("wz_debug_net_log_level", String.valueOf(WOWZLog.LOG_LEVEL_DEBUG)));
mStreamPlayerConfig.setIsPlayback(true);
if (mStreamPlayerConfig != null)
GoCoderSDKPrefs.updateConfigFromPrefsForPlayer(prefs, mStreamPlayerConfig);
}
private class StatusCallback implements WOWZStatusCallback {
#Override
public void onWZStatus(WOWZStatus wzStatus) {
}
#Override
public void onWZError(WOWZStatus wzStatus) {
}
}
}
The error I get is;
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.wowza.gocoder.sdk.sampleapp/com.wowza.gocoder.sdk.sampleapp.PlayerActivity}: java.lang.RuntimeException: Invalid surface: null
You start the stream in onCreate. At this time the Surface used by WOWZPlayerView is not ready yet and the app crashes with the 'Invalid surface' error.
If you look at the sample test in the GoCoder SDK, the playback is started when the user clicks a button. Eg. when the Surface is valid.
Create a button and move your 'mStreamPlayerView.play(mStreamPlayerConfig, statusCallback);' to the button.onClick.
Or ... use any GoCoder SDK v1.7 and more recent.
Please, let me know if I can help any further.
Thanks
I do not know much about android. I am trying to send data over BLE.my code is as follows->. I got it from internet https://developer.android.com/guide/topics/connectivity/bluetooth-le#read
how to properly call this method-> mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);There is crash on this line.
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
public BluetoothManager mBluetoothManager;
public BluetoothAdapter mBluetoothAdapter;
public String mBluetoothDeviceAddress;
public BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private final IBinder mBinder = new LocalBinder();
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
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 =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Various callback methods defined by the BLE API.
public final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000ffe9-0000-1000-8000-00805f9b34fb")) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//...
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
public static String byteToHexStr(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data
// parsing is carried out as per profile specifications.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
stringBuilder.toString());
}
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;/*return null;*/
}
//...
}
I am calling this class methods from outside like this->
public class DeviceScanActivity extends AppCompatActivity/*ListActivity*/ {
//private LeDeviceListAdapter mLeDeviceListAdapter;
public BluetoothAdapter mBluetoothAdapter;
public /*final*/ BluetoothManager mBluetoothManager;
/*=(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);;*/
private BluetoothLeService mBluetoothService;//= new BluetoothLeService();
public Context cntxt;
ArrayList<ViewHolder> arrayOfUsers2 = new ArrayList<ViewHolder>();
private boolean mScanning;
private boolean mBounded;
private Handler mHandler;
ArrayList<String> mylist = new ArrayList<String>();
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 50000;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 456;
UsersAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//getActionBar().setTitle("abc");
mHandler = new Handler();
//this.requestPermissions(rqPerm,req);
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
/*final BluetoothManager*/ mBluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null ) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
if( !mBluetoothAdapter.isEnabled())
{
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(getIntent(), 1);
}
// Construct the data source
ArrayList<ViewHolder> arrayOfUsers = new ArrayList<ViewHolder>();
// Create the adapter to convert the array to views
adapter = new UsersAdapter(this, arrayOfUsers);
cntxt=this.getApplicationContext();
Intent i = new Intent(this, BluetoothLeService.class);
bindService(this.getIntent(), mConnection, BIND_AUTO_CREATE);; //if checked, start service
ListView listView = (ListView) findViewById(R.id.mobile_list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ViewHolder entry= (ViewHolder) parent.getAdapter().getItem(position);
String address = entry.deviceAddress;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
Toast.makeText(cntxt, address, Toast.LENGTH_SHORT).show();
//mBluetoothService.mBluetoothDeviceAddress=address;
//mBluetoothService.mBluetoothManager=mBluetoothManager;
mBluetoothService.mBluetoothAdapter = mBluetoothAdapter;
mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);
//Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
}});
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
}
ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
//Toast.makeText(Client.this, "Service is disconnected", 1000).show();
mBounded = false;
mBluetoothService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
//Toast.makeText(Client.this, "Service is connected", 1000).show();
mBounded = true;
BluetoothLeService.LocalBinder mLocalBinder = (BluetoothLeService.LocalBinder)service;
mBluetoothService = mLocalBinder.getService();
}
};
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
Iterator<ViewHolder> it=arrayOfUsers2.iterator();
while(it.hasNext()) {
ViewHolder currentX = it.next();
adapter.add(currentX);
}
// Do something with the value
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
//invalidateOptionsMenu();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, yay! Start the Bluetooth device scan.
scanLeDevice(true);
} else {
// Alert the user that this application requires the location permission to perform the scan.
}
}
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//mLeDeviceListAdapter.addDevice(device);
//mLeDeviceListAdapter.notifyDataSetChanged();
//ViewHolder newUser = new ViewHolder("Nathan", "San Diego");
String deviceName=null, deviceAddress=null;
if(device!=null)
deviceName= device.getName();
if (!(deviceName != null && deviceName.length() > 0))
deviceName = "unknown device";
if(device!=null)
deviceAddress= device.getAddress();
ViewHolder newUser = new ViewHolder(deviceName, deviceAddress);
ViewHolder newUser2 = new ViewHolder("adtv","vvg");
if(!arrayOfUsers2.contains(newUser))
arrayOfUsers2.add(newUser);
//adapter.add(newUser);
}
});
}
};
public class UsersAdapter extends ArrayAdapter<ViewHolder> {
public UsersAdapter(Context context, ArrayList<ViewHolder> users) {
super(context, 0, users);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ViewHolder user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bt_details, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.DeviceName);
TextView tvHome = (TextView) convertView.findViewById(R.id.DeviceAddress);
// Populate the data into the template view using the data object
tvName.setText(user.deviceName);
tvHome.setText(user.deviceAddress);
// Return the completed view to render on screen
return convertView;
}
}
public class ViewHolder {
String deviceName;
String deviceAddress;
public ViewHolder(String device, String __address) {
this.deviceName =device;
this.deviceAddress= __address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ViewHolder a = (ViewHolder) o;
return Objects.equals(deviceAddress, a.deviceAddress);
}
}
}
where I get scan device results in a list. On clicking anyelement of that list I invoke AdapterView.OnItemClickListener(). Then how to send message to the device. How to read those log messages. How to know if the code has send message. How to receive message in other device.I have already done BLE scan, which working fine.But not added the code here.
the log cat report is as follows
FATAL EXCEPTION: main
Process: com.example.root.securityalert, PID: 27945
java.lang.NullPointerException: Attempt to read from field 'android.bluetooth.BluetoothGattCallback com.example.root.securityalert.BluetoothLeService.mGattCallback' on a null object reference
at com.example.root.securityalert.DeviceScanActivity$1.onItemClick(DeviceScanActivity.java:115)
at android.widget.AdapterView.performItemClick(AdapterView.java:310)
at android.widget.AbsListView.performItemClick(AbsListView.java:1156)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3147)
at android.widget.AbsListView$3.run(AbsListView.java:4062)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6165)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)
I also tried with the code
public class BluetoothSendRecv extends BluetoothGattCallback{
public BluetoothManager mBluetoothManager;
public BluetoothAdapter mBluetoothAdapter;
public String mBluetoothDeviceAddress;
public BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
// private final IBinder mBinder = new BluetoothLeService.LocalBinder();
public Context cntxt;
.......
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Various callback methods defined by the BLE API.
public final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/)) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
//Toast.makeText(this., "R.string.error_bluetooth_not_supported", Toast.LENGTH_SHORT).show();
//finish()
System.out.println("Writing Mithun");
Toast.makeText(cntxt, originalString, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//...
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
//sendBroadcast(intent);
}
.....
}
Then logcat report is as follows aaaa
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=CC:1E:39:39:62:1C
I/ContentValues: Connected to GATT server.
D/BluetoothGatt: discoverServices() - device: CC:1E:39:39:62:1C
I/ContentValues: Attempting to start service discovery:true
D/BluetoothGatt: onSearchComplete() = Device=CC:1E:39:39:62:1C Status=0
I/ContentValues: onServicesDiscovered: ---------------------
I/ContentValues: onServicesDiscovered: service=00001800-0000-1000-8000-00805f9b34fb
I/ContentValues: onServicesDiscovered: characteristic=00002a00-0000-1000-8000-00805f9b34fb
I think this condition is not fullfilled
if(characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/))
I think you must add "Scan" method before try connect.This is rule of ble architecture.Like this :
private void startScanning(final boolean enable, BluetoothAdapter mBluetoothAdapter) {
bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
List<ScanFilter> scanFilters = new ArrayList<>();
final ScanSettings settings = new ScanSettings.Builder().build();
ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(UUID_SERVICE)).build();
scanFilters.add(scanFilter);
bluetoothLeScanner.startScan(scanFilters, settings, scanCallback);
}
And if Ble Device is founded :
ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
bluetoothDevice = result.getDevice();
Log.d(TAG, "onScanResult: bluetoothDevice.getAddress());
mScanning = false;
String adress = bluetoothDevice.getAddress();
bluetoothLeScanner.stopScan(scanCallback);
connect(bluetoothDevice);
}
I am developing an Android app to control stepper motors via a Android Due and a Bluetooth HM-10 BLE module.
So far everything works, but there seems to be a problem on some devices, which cause the app to crash. On my Nexus 5 and 7 it is working fine, but for example on a Samsung Galaxy S5 it keeps crashing. All devices have Andoird 6.0.1, so they should be equal.
I am getting this error report from the user:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattCharacteristic.setValue(byte[])' on a null object reference
at pm.puremoco.BluetoothLeService.WriteValue(BluetoothLeService.java:70)
at pm.puremoco.frag_moviesetlinear$3.onFinish(frag_moviesetlinear.java:266)
at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:127)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
So the error is occuring, when opening, at "onCreateView". There is the command to transmit a value:
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
Here is almost the full fragment:
public class frag_moviesetlinear extends Fragment {
public static final String methodtocall = "ooo";
private final static String TAG = DeviceControlFragment.class.getSimpleName();
public AlertDialog alertTransmitData;
public BluetoothLeService mBluetoothLeService; //TODO evtl. private
public String methodcalled = "aaa";
public String dataLineReceived;
public long countDownTimerDelay = 200;
public AlertDialog alertTimeTooShort;
NumberPicker noPick1 = null;
NumberPicker noPick2 = null;
NumberPicker noPick3 = null;
long alertTransmitDataLength = 21000;
DeviceControlFragment devConFrag;
double minTimeFactor = 0;
TextView vid_maxSpeedU;
TextView vid_maxSpeedV;
TextView vid_maxSpeedW;
TextView vid_maxSpeedX;
TextView vid_maxSpeedY;
TextView vid_maxSpeedZ;
TextView vid_maxSpeedUspline;
TextView vid_maxSpeedVspline;
TextView vid_maxSpeedWspline;
TextView vid_maxSpeedXspline;
TextView vid_maxSpeedYspline;
TextView vid_maxSpeedZspline;
TextView txt_vidDuration;
TextView txt_vidUpdateIntervall;
TextView txt_minTime;
int timeForCalculation = 0;
int calculatedSpeedU = 0;
int calculatedSpeedV = 0;
int calculatedSpeedW = 0;
int calculatedSpeedX = 0;
int calculatedSpeedY = 0;
int calculatedSpeedZ = 0;
boolean movingHome = false;
private String mDeviceAddress;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
getActivity().finish();
}
Log.e(TAG, "mBluetoothLeService is okay");
// Log.e(TAG, mDeviceAddress);
// Automatically connects to the device upon successful start-up initialization.
if (mDeviceAddress == "---") {
Toast.makeText(getActivity(), "Bluetooth-Device not selected!", Toast.LENGTH_SHORT).show();
} else {
mBluetoothLeService.connect(mDeviceAddress);
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private String mDeviceName;
private TextView mDataField;
private Button btn_vidSplineStart;
private Button btn_vidUpdateIntervalNeg;
private Button btn_vidUpdateIntervalPos;
private boolean mConnected = false;
// 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(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { //���ӳɹ�
Log.e(TAG, "Only gatt, just wait");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { //�Ͽ�����
mConnected = false;
getActivity().invalidateOptionsMenu();
// btnSend.setEnabled(false);
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) //���Կ�ʼ�ɻ���
{
mConnected = true;
// mDataField.setText("");
// ShowDialog();
//btnSend.setEnabled(true);
Log.e(TAG, "In what we need");
getActivity().invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { //�յ�����
Log.e(TAG, "RECV DATA");
final String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
Log.e(TAG, data);
if (data != null && data.substring(0, 1).equals("#") && data.substring(data.length() - 1).equals("$")) {
// if (mDataField.length() > 500)
// mDataField.setText("");
// mDataField.append(data);
dataLineReceived = data.substring(1, data.length() - 1);
ActionHandlerDataReceived();
}
}
}
};
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);
intentFilter.addAction(BluetoothDevice.ACTION_UUID);
return intentFilter;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final Intent intent = getActivity().getIntent();
// mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
// mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
mDeviceAddress = variables.BluetoothAddress;
mDeviceName = variables.BluetoothName;
methodcalled = intent.getStringExtra(methodtocall);
Intent gattServiceIntent = new Intent(getActivity(), BluetoothLeService.class);
Log.d(TAG, "Try to bindService=" + getActivity().bindService(gattServiceIntent, mServiceConnection, getActivity().BIND_AUTO_CREATE));
getActivity().registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
#Override
public void onPause() {
super.onPause();
try {
getActivity().unregisterReceiver(mGattUpdateReceiver);
}
catch(Exception e){
}
try {
getActivity().unbindService(mServiceConnection);
}
catch(Exception e){
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "We are in destroy");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.setmovie, null);
vid_maxSpeedU = (TextView) layout.findViewById(R.id.vid_maxSpeedU);
vid_maxSpeedU.setText(String.valueOf(variables.speedU));
vid_maxSpeedV = (TextView) layout.findViewById(R.id.vid_maxSpeedV);
vid_maxSpeedV.setText(String.valueOf(variables.speedV));
vid_maxSpeedW = (TextView) layout.findViewById(R.id.vid_maxSpeedW);
vid_maxSpeedW.setText(String.valueOf(variables.speedW));
vid_maxSpeedX = (TextView) layout.findViewById(R.id.vid_maxSpeedX);
vid_maxSpeedX.setText(String.valueOf(variables.speedX));
vid_maxSpeedY = (TextView) layout.findViewById(R.id.vid_maxSpeedY);
vid_maxSpeedY.setText(String.valueOf(variables.speedY));
vid_maxSpeedZ = (TextView) layout.findViewById(R.id.vid_maxSpeedZ);
vid_maxSpeedZ.setText(String.valueOf(variables.speedZ));
double duration = 3700 * (double) variables.vidUpdateIntervall / 1000;
txt_vidUpdateIntervall = (TextView) layout.findViewById(R.id.txt_vidUpdateIntervall);
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
txt_vidDuration = (TextView) layout.findViewById(R.id.txt_vidDuration);
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
vid_maxSpeedUspline = (TextView) layout.findViewById(R.id.vid_maxSpeedUspline);
vid_maxSpeedVspline = (TextView) layout.findViewById(R.id.vid_maxSpeedVspline);
vid_maxSpeedWspline = (TextView) layout.findViewById(R.id.vid_maxSpeedWspline);
vid_maxSpeedXspline = (TextView) layout.findViewById(R.id.vid_maxSpeedXspline);
vid_maxSpeedYspline = (TextView) layout.findViewById(R.id.vid_maxSpeedYspline);
vid_maxSpeedZspline = (TextView) layout.findViewById(R.id.vid_maxSpeedZspline);
txt_minTime = (TextView) layout.findViewById(R.id.txt_minTime);
btn_vidSplineStart = (Button) layout.findViewById(R.id.btn_vidSplineStart);
btn_vidSplineStart.setOnClickListener(new event_btn_vidSplineStart());
btn_vidUpdateIntervalPos = (Button) layout.findViewById(R.id.btn_vidUpdateIntervalPos);
btn_vidUpdateIntervalPos.setOnClickListener(new event_btn_vidUpdateIntervalPos());
btn_vidUpdateIntervalNeg = (Button) layout.findViewById(R.id.btn_vidUpdateIntervalNeg);
btn_vidUpdateIntervalNeg.setOnClickListener(new event_btn_vidUpdateIntervalNeg());
//-----start-button------
minTimeFactor = 0;
timeForCalculation = variables.vidUpdateIntervall;
new CountDownTimer(countDownTimerDelay * 1, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
}
}.start();
new CountDownTimer(countDownTimerDelay * 2, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mBluetoothLeService.WriteValue("2000_" + String.valueOf(variables.linearWithFade) + "#");
}
}.start();
//-----start-button------
transmitDataAlert("calculation");
return layout;
}
private void ActionHandlerDataReceived() {
String variable;
String value;
String[] parts = dataLineReceived.split("_"); // escape .
variable = parts[0];
value = parts[1];
switch (variable) {
case "vidMaxSpeedU":
vid_maxSpeedUspline.setText(String.valueOf(value));
variables.vid_maxSpeedUspline = Integer.parseInt(value);
calculatedSpeedU = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedU) {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorU = Double.valueOf(value) / variables.speedU;
if (minTimeFactor < FactorU) {
minTimeFactor = FactorU;
}
break;
case "vidMaxSpeedV":
vid_maxSpeedVspline.setText(String.valueOf(value));
variables.vid_maxSpeedVspline = Integer.parseInt(value);
calculatedSpeedV = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedV) {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorV = Double.valueOf(value) / variables.speedV;
if (minTimeFactor < FactorV) {
minTimeFactor = FactorV;
}
break;
case "vidMaxSpeedW":
vid_maxSpeedWspline.setText(String.valueOf(value));
variables.vid_maxSpeedWspline = Integer.parseInt(value);
calculatedSpeedW = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedW) {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorW = Double.valueOf(value) / variables.speedW;
if (minTimeFactor < FactorW) {
minTimeFactor = FactorW;
}
break;
case "vidMaxSpeedX":
vid_maxSpeedXspline.setText(String.valueOf(value));
variables.vid_maxSpeedXspline = Integer.parseInt(value);
calculatedSpeedX = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedX) {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorX = Double.valueOf(value) / variables.speedX;
if (minTimeFactor < FactorX) {
minTimeFactor = FactorX;
}
break;
case "vidMaxSpeedY":
vid_maxSpeedYspline.setText(String.valueOf(value));
variables.vid_maxSpeedYspline = Integer.parseInt(value);
calculatedSpeedY = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedY) {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorY = Double.valueOf(value) / variables.speedY;
if (minTimeFactor < FactorY) {
minTimeFactor = FactorY;
}
break;
case "vidMaxSpeedZ":
vid_maxSpeedZspline.setText(String.valueOf(value));
variables.vid_maxSpeedZspline = Integer.parseInt(value);
calculatedSpeedZ = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedZ) {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorZ = Double.valueOf(value) / variables.speedZ;
if (minTimeFactor < FactorZ) {
minTimeFactor = FactorZ;
}
alertTransmitData.dismiss();
double vidMin = Math.ceil(minTimeFactor * timeForCalculation);
variables.vidMinIntervall = (int) vidMin;
//txt_minTime.setText(String.valueOf(variables.vidMinIntervall));
double duration = (3700 * (double) variables.vidMinIntervall) / 1000;
txt_minTime.setText(String.format("%.2f", duration) + " s");
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
break;
case "movieFinished":
btn_vidSplineStart.setText("Move home");
btn_vidSplineStart.setEnabled(true);
movingHome = true;
alertTransmitData.dismiss();
break;
case "movieHome":
btn_vidSplineStart.setText("Start");
btn_vidSplineStart.setEnabled(true);
alertTransmitData.dismiss();
break;
}
}
void calculateNewSpeeds() {
//--------------U-Axis-----------------
if (variables.vid_maxSpeedUspline != 0) {
variables.vid_maxSpeedUspline = (timeForCalculation * calculatedSpeedU) / variables.vidUpdateIntervall;
vid_maxSpeedUspline.setText(String.valueOf(variables.vid_maxSpeedUspline));
if (variables.vid_maxSpeedUspline > variables.speedU) {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------V-Axis-----------------
if (variables.vid_maxSpeedVspline != 0) {
variables.vid_maxSpeedVspline = (timeForCalculation * calculatedSpeedV) / variables.vidUpdateIntervall;
vid_maxSpeedVspline.setText(String.valueOf(variables.vid_maxSpeedVspline));
if (variables.vid_maxSpeedVspline > variables.speedV) {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------W-Axis-----------------
if (variables.vid_maxSpeedWspline != 0) {
variables.vid_maxSpeedWspline = (timeForCalculation * calculatedSpeedW) / variables.vidUpdateIntervall;
vid_maxSpeedWspline.setText(String.valueOf(variables.vid_maxSpeedWspline));
if (variables.vid_maxSpeedWspline > variables.speedW) {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------X-Axis-----------------
if (variables.vid_maxSpeedXspline != 0) {
variables.vid_maxSpeedXspline = (timeForCalculation * calculatedSpeedX) / variables.vidUpdateIntervall;
vid_maxSpeedXspline.setText(String.valueOf(variables.vid_maxSpeedXspline));
if (variables.vid_maxSpeedXspline > variables.speedX) {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------Y-Axis-----------------
if (variables.vid_maxSpeedYspline != 0) {
variables.vid_maxSpeedYspline = (timeForCalculation * calculatedSpeedY) / variables.vidUpdateIntervall;
vid_maxSpeedYspline.setText(String.valueOf(variables.vid_maxSpeedYspline));
if (variables.vid_maxSpeedYspline > variables.speedY) {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------Z-Axis-----------------
if (variables.vid_maxSpeedZspline != 0) {
variables.vid_maxSpeedZspline = (timeForCalculation * calculatedSpeedZ) / variables.vidUpdateIntervall;
vid_maxSpeedZspline.setText(String.valueOf(variables.vid_maxSpeedZspline));
if (variables.vid_maxSpeedZspline > variables.speedZ) {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
}
public void alert_TimeTooShort(int errorCase, int movieLengthSecondsNEW) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
getActivity());
// set title
alertDialogBuilder.setTitle("Error");
String errorMessage = "error";
// set dialog message
alertDialogBuilder
.setMessage(errorMessage)
.setCancelable(false);
alertDialogBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
}
});
// create alert dialog
alertTimeTooShort = alertDialogBuilder.create();
// show it
alertTimeTooShort.show();
}
public void transmitDataAlert(String type) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View promptView = layoutInflater.inflate(R.layout.alert_transmitdata, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setView(promptView);
final ProgressBar progressbar = (ProgressBar) promptView.findViewById(R.id.progressBar_transmitData);
final TextView txt_PleaseWait = (TextView) promptView.findViewById(R.id.txt_PleaseWait);
final TextView txt_timeRemainVideo = (TextView) promptView.findViewById(R.id.txt_timeRemainVideo);
final TextView txt_timeRemainVideoTXT = (TextView) promptView.findViewById(R.id.txt_timeRemainVideoTXT);
new CountDownTimer(alertTransmitDataLength, 1) {
public void onTick(long millisUntilFinished) {
int longtointRemain = (int) millisUntilFinished;
int longtointFull = (int) alertTransmitDataLength;
int percentprogress = 100 - ((100 * longtointRemain) / longtointFull);
progressbar.setProgress(percentprogress);
float duration = (float) millisUntilFinished/1000;
txt_timeRemainVideo.setText(String.format("%.1f", duration) + " s");
}
public void onFinish() {
}
}.start();
}
alertDialogBuilder.setCancelable(false);
alertTransmitData = alertDialogBuilder.create();
alertTransmitData.show();
}
class event_btn_vidSplineStart implements View.OnClickListener {
#Override
public void onClick(View v) {
btn_vidSplineStart.setEnabled(false);
btn_vidSplineStart.setText("Moving...");
new CountDownTimer(countDownTimerDelay * 1, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//MotionMode
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
}
}.start();
new CountDownTimer(countDownTimerDelay * 2, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//MotionMode
mBluetoothLeService.WriteValue("1110_0#");
}
}.start();
alertTransmitDataLength = (long) variables.vidUpdateIntervall*3700;
if(movingHome==true){
transmitDataAlert("moveHome");
movingHome=false;
}
else {
transmitDataAlert("videomove");
}
}
}
class event_btn_vidUpdateIntervalPos implements View.OnClickListener {
#Override
public void onClick(View v) {
variables.vidUpdateIntervall++;
double duration = (3700 * (double) variables.vidUpdateIntervall) / 1000;
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
calculateNewSpeeds();
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
else{
btn_vidSplineStart.setEnabled(false);
}
}
}
class event_btn_vidUpdateIntervalNeg implements View.OnClickListener {
#Override
public void onClick(View v) {
if (variables.vidUpdateIntervall > 1) {
variables.vidUpdateIntervall--;
}
double duration = (3700 * (double) variables.vidUpdateIntervall) / 1000;
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
calculateNewSpeeds();
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
else{
btn_vidSplineStart.setEnabled(false);
}
}
}
}
And here is the full BluetoothLeService, which I got from the website of the HM-10 Bluetooth manufacturer:
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.util.List;
import java.util.UUID;
/**
* 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();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
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 =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_NOTIFY =
UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_SERVICE =
UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
public BluetoothGattCharacteristic mNotifyCharacteristic;
public void WriteValue(String strValue)
{
mNotifyCharacteristic.setValue(strValue.getBytes());
mBluetoothGatt.writeCharacteristic(mNotifyCharacteristic);
}
public void findService(List<BluetoothGattService> gattServices)
{
Log.i(TAG, "Count is:" + gattServices.size());
for (BluetoothGattService gattService : gattServices)
{
Log.i(TAG, gattService.getUuid().toString());
Log.i(TAG, UUID_SERVICE.toString());
if(gattService.getUuid().toString().equalsIgnoreCase(UUID_SERVICE.toString()))
{
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
Log.i(TAG, "Count is:" + gattCharacteristics.size());
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics)
{
if(gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_NOTIFY.toString()))
{
Log.i(TAG, gattCharacteristic.getUuid().toString());
Log.i(TAG, UUID_NOTIFY.toString());
mNotifyCharacteristic = gattCharacteristic;
setCharacteristicNotification(gattCharacteristic, true);
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
return;
}
}
}
}
}
// 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(BluetoothGatt gatt, int status, int newState) {
String intentAction;
Log.i(TAG, "oldStatus=" + status + " NewStates=" + newState);
if(status == BluetoothGatt.GATT_SUCCESS)
{
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_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());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mBluetoothGatt.close();
mBluetoothGatt = null;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered received: " + status);
findService(gatt.getServices());
} else {
if(mBluetoothGatt.getDevice().getUuids() == null)
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
Log.e(TAG, "OnCharacteristicWrite");
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status)
{
Log.e(TAG, "OnCharacteristicWrite");
}
#Override
public void onDescriptorRead(BluetoothGatt gatt,
BluetoothGattDescriptor bd,
int status) {
Log.e(TAG, "onDescriptorRead");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor bd,
int status) {
Log.e(TAG, "onDescriptorWrite");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int a, int b)
{
Log.e(TAG, "onReadRemoteRssi");
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int a)
{
Log.e(TAG, "onReliableWriteCompleted");
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
//final StringBuilder stringBuilder = new StringBuilder(data.length);
//for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
//intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
intent.putExtra(EXTRA_DATA, new String(data));
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(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);
}
private final IBinder mBinder = new LocalBinder();
/**
* 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;
}
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;
}
/*
// Previously connected device. Try to reconnect.
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;
} else {
return false;
}
}
*/
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.
if(mBluetoothGatt != null)
{
mBluetoothGatt.close();
mBluetoothGatt = null;
}
mBluetoothGatt = device.connectGatt(this.getApplication(), false, mGattCallback);
//mBluetoothGatt.connect();
Log.d(TAG, "Trying to create a new connection.");
return true;
}
/**
* 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(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(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
/*
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
*/
}
/**
* 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();
}
}