我正在尝试通过蓝牙低功耗连接两个Android设备(带有Android 7的Galaxy J5和带有Android 6.0.1的Redmi Note 3),因此Galaxy充当外围设备,而Redmi充当中央设备。
我称Galaxy为“ XY”。我希望Redmi在我创建的自定义服务中编写一些内容,然后使Galaxy显示Toast。
我或多或少地遵循了本教程http://nilhcem.com/android-things/bluetooth-low-energy,并尝试了一些我在其他答案中看到的修复程序,例如在BluetoothGatt的每个操作之间增加了延迟,但到目前为止没有任何效果。
在ScanCallback中,当我调用System.out.println(result.getScanRecord().getServiceUuids())
时,它会打印我的服务的UUID,但是在onServicesDiscovered中,当我调用BluetoothGattCharacteristic characteristic = gatt.getService(SERVICE_UUID).getCharacteristic(WRITE_UUID);
时,它会给我一个NullPointerException,如果我打印每个服务UUID,它永远不会显示我的自定义服务UUID。
这是代码:
public class MainActivity extends AppCompatActivity {
public Context mContext;
public BluetoothAdapter bt;
public final int REQUEST_ENABLE_BT = 1;
public BluetoothLeScanner LEScanner;
public BluetoothGatt mGatt;
public boolean scanning;
public Handler mHandler = new Handler();
public static final long SCAN_PERIOD = 10000; //ms
public List<BluetoothDevice> LEDevices = new ArrayList<>();
public final UUID SERVICE_ID = UUID.fromString("36afe8c7-a825-4ac0-b06c-0279645421c6");
public final UUID SERVICE_UUID = UUID.fromString("6907ff35-cc36-4872-a5a6-c01a4b3017bc");
public final UUID WRITE_UUID = UUID.fromString("64e68646-8257-4e1e-a697-1cbc07488e05");
public Button clientButton, serverButton;
public boolean connecting = false;
//Server
public BluetoothGattServer mGattServer;
public BluetoothGattCallback gattCallback;
public BluetoothLeAdvertiser advertiser;
public AdvertiseSettings settings = new AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH).setConnectable(false).setTimeout(0).build();
public ParcelUuid pUuid = new ParcelUuid(SERVICE_ID);
public AdvertiseData data = new AdvertiseData.Builder().setIncludeDeviceName(true).addServiceUuid(pUuid).setIncludeTxPowerLevel(false).build();
public BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
@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 (characteristic.getUuid().equals(WRITE_UUID)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "Hey, its redmi!", Toast.LENGTH_SHORT);
}
});
}
}
};
public AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "Comenzado con MAC " + bt.getAddress() + ";", Toast.LENGTH_SHORT).show();
}
});
mGattServer = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE)).openGattServer(mContext, mGattServerCallback);
final BluetoothGattService service = createService();
mGattServer.addService(service);
System.out.println(mGattServer.getServices().get(0).getUuid());
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "Service UUID: " + mGattServer.getServices().get(0).getUuid(), Toast.LENGTH_SHORT).show();
Toast.makeText(mContext, "Characteristic UUID: " + mGattServer.getServices().get(0).getCharacteristics().get(0).getUuid(), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
System.out.println(errorCode);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = getApplicationContext();
clientButton = findViewById(R.id.clientButton);
serverButton = findViewById(R.id.serverButton);
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE not supported, exiting...", Toast.LENGTH_SHORT).show();
finish();
}
bt = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
if(bt == null || !bt.isEnabled()) {
Intent enableBT = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBT, REQUEST_ENABLE_BT);
}
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION}, 1);
LEScanner = bt.getBluetoothLeScanner();
advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
clientButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scanLeDevice(true);
}
});
serverButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runOnUiThread(new Runnable() {
@Override
public void run() {
advertiser.startAdvertising(settings, data, advertisingCallback);
}
});
}
});
gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if(newState == BluetoothProfile.STATE_CONNECTED){
scanLeDevice(false);
System.out.println("********** DISCOVERING **********");
SystemClock.sleep(3000);
gatt.discoverServices();
System.out.println("Discovered");
}
else{
scanLeDevice(false);
gatt.close();
scanLeDevice(true);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if(status == BluetoothGatt.GATT_SUCCESS){
SystemClock.sleep(3000);
System.out.println("Success discovering: writing");
//TODO: NOT WORKING
BluetoothGattCharacteristic characteristic = gatt.getService(SERVICE_UUID).getCharacteristic(WRITE_UUID);
System.out.println(characteristic.toString());
//System.exit(0);
/*System.out.println(gatt.getService(SERVICE_UUID).toString());
BluetoothGattCharacteristic writeChar = gatt.getService(SERVICE_UUID).getCharacteristic(WRITE_UUID);
byte[] data = new byte[10];
writeChar.setValue(data);
gatt.writeCharacteristic(writeChar);
System.out.println("WRITTEN DATA");*/
}
else{
System.out.println(status);
scanLeDevice(false);
}
}
};
}
private ScanCallback LEScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if(!connecting) {
if (result == null || result.getDevice() == null || result.getScanRecord().getDeviceName() == null)
return;
System.out.println("******* ON SCAN RESULT ********");
System.out.println(result.getScanRecord().getDeviceName());
System.out.println(result.getScanRecord().getServiceUuids());
System.out.println(result.getScanRecord().getAdvertiseFlags());
System.out.println(result.getDevice().toString());
System.out.println(result.getDevice().getAddress());
if (result.getScanRecord().getDeviceName().equals("XY")) {
connecting = true;
System.out.println("******** DEVICE FOUND *********");
System.out.println(result.getDevice().toString());
connectToDeviceLE(result.getDevice().getAddress());
}
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
System.out.println("******* ON BATCH SCAN RESULT ********");
for (ScanResult sr : results){
System.out.println(sr.toString());
}
}
@Override
public void onScanFailed(int errorCode) {
System.out.println("******* ON SCAN FAILED ********");
}
};
private void scanLeDevice(final boolean enable){
if(enable){
mHandler.postDelayed(new Runnable(){
@Override
public void run() {
scanning = false;
LEScanner.stopScan(LEScanCallback);
connecting = false;
}
}, SCAN_PERIOD);
scanning = true;
LEScanner.startScan(LEScanCallback);
}
else{
scanning = false;
LEScanner.stopScan(LEScanCallback);
connecting = false;
}
}
public void connectToDeviceLE(String deviceAddress){
final BluetoothDevice device = bt.getRemoteDevice(deviceAddress);
scanLeDevice(false);
SystemClock.sleep(3000);
mGatt = device.connectGatt(mContext, false, gattCallback);
//System.out.println(mGatt.toString());
}
private BluetoothGattService createService(){
BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic interactor = new BluetoothGattCharacteristic(WRITE_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, BluetoothGattCharacteristic.PERMISSION_WRITE);
service.addCharacteristic(interactor);
return service;
}