Last active
November 26, 2017 17:15
-
-
Save ntoto/873fb80355254a77de0f64c50b3e486b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.toto.lmlm; | |
import android.annotation.TargetApi; | |
import android.app.Activity; | |
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.bluetooth.le.BluetoothLeScanner; | |
import android.bluetooth.le.ScanCallback; | |
import android.bluetooth.le.ScanFilter; | |
import android.bluetooth.le.ScanResult; | |
import android.bluetooth.le.ScanSettings; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.pm.PackageManager; | |
import android.os.Build; | |
import android.os.Handler; | |
import android.os.ParcelUuid; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.widget.Toast; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.UUID; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.ScheduledExecutorService; | |
import java.util.concurrent.TimeUnit; | |
@TargetApi(21) | |
public class MainScreen extends AppCompatActivity { | |
private BluetoothAdapter mBluetoothAdapter; | |
private int REQUEST_ENABLE_BT = 1; | |
private Handler mHandler; | |
private static final long SCAN_PERIOD = 10000; | |
private BluetoothLeScanner mLEScanner; | |
private ScanSettings settings; | |
private List<ScanFilter> filters; | |
private BluetoothGatt mGatt; | |
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); | |
private boolean notificationInfoSent; | |
private String SCALE_SERVICE_UUID = "00001820-0000-1000-8000-00805f9b34fb"; | |
private String SCALE_CHARACTERISTIC_UUID = "00002a80-0000-1000-8000-00805f9b34fb"; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main_screen); | |
mHandler = new Handler(); | |
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { | |
Toast.makeText(this, "BLE Not Supported", Toast.LENGTH_SHORT).show(); | |
finish(); | |
} | |
final BluetoothManager bluetoothManager = | |
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); | |
mBluetoothAdapter = bluetoothManager.getAdapter(); | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { | |
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); | |
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); | |
} | |
else { | |
if (Build.VERSION.SDK_INT >= 21) { | |
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner(); | |
settings = new ScanSettings.Builder() | |
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) | |
.build(); | |
filters = new ArrayList<>(); | |
filters.add( | |
new ScanFilter | |
.Builder() | |
.setServiceUuid(ParcelUuid.fromString(SCALE_SERVICE_UUID)) | |
.build() | |
); | |
} | |
scanLeDevice(true); | |
} | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { | |
scanLeDevice(false); | |
} | |
} | |
@Override | |
protected void onDestroy() { | |
if (mGatt == null) { | |
return; | |
} | |
mGatt.close(); | |
mGatt = null; | |
super.onDestroy(); | |
} | |
@Override | |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
if (requestCode == REQUEST_ENABLE_BT) { | |
if (resultCode == Activity.RESULT_CANCELED) { | |
//Bluetooth not enabled. | |
finish(); | |
return; | |
} | |
} | |
super.onActivityResult(requestCode, resultCode, data); | |
} | |
private void scanLeDevice(final boolean enable) { | |
if (enable) { | |
mHandler.postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
if (Build.VERSION.SDK_INT < 21) { | |
mBluetoothAdapter.stopLeScan(mLeScanCallback); | |
} else { | |
mLEScanner.stopScan(mScanCallback); | |
} | |
} | |
}, SCAN_PERIOD); | |
if (Build.VERSION.SDK_INT < 21) { | |
mBluetoothAdapter.startLeScan(mLeScanCallback); | |
} else { | |
mLEScanner.startScan(filters, settings, mScanCallback); | |
} | |
} | |
else { | |
if (Build.VERSION.SDK_INT < 21) { | |
mBluetoothAdapter.stopLeScan(mLeScanCallback); | |
} else { | |
mLEScanner.stopScan(mScanCallback); | |
} | |
} | |
} | |
private ScanCallback mScanCallback = new ScanCallback() { | |
@Override | |
public void onScanResult(int callbackType, ScanResult result) { | |
Log.i("callbackType", String.valueOf(callbackType)); | |
Log.i("result", result.toString()); | |
BluetoothDevice btDevice = result.getDevice(); | |
connectToDevice(btDevice); | |
} | |
@Override | |
public void onBatchScanResults(List<ScanResult> results) { | |
for (ScanResult sr : results) { | |
Log.i("ScanResult - Results", sr.toString()); | |
} | |
} | |
@Override | |
public void onScanFailed(int errorCode) { | |
Log.e("Scan Failed", "Error Code: " + errorCode); | |
} | |
}; | |
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() { | |
Log.i("onLeScan", device.toString()); | |
connectToDevice(device); | |
} | |
}); | |
} | |
}; | |
public void connectToDevice(BluetoothDevice device) { | |
if (mGatt == null) { | |
mGatt = device.connectGatt(this, false, gattCallback); | |
// will stop after first device detection | |
scanLeDevice(false); | |
} | |
} | |
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { | |
@Override | |
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { | |
Log.i("onConnectionStateChange", "Status: " + status); | |
switch (newState) { | |
case BluetoothProfile.STATE_CONNECTED: | |
Log.i("gattCallback", "STATE_CONNECTED"); | |
gatt.discoverServices(); | |
break; | |
case BluetoothProfile.STATE_DISCONNECTED: | |
Log.e("gattCallback", "STATE_DISCONNECTED"); | |
break; | |
default: | |
Log.e("gattCallback", "STATE_OTHER"); | |
} | |
} | |
private void sendMessage(int type, byte[] payload) { | |
int cksum1 = 0; | |
int cksum2 = 0; | |
byte[] bytes = new byte[payload.length + 5]; | |
bytes[0] = (byte)0xef; | |
bytes[1] = (byte)0xdd; | |
bytes[2] = (byte)type; | |
for (int i = 0; i < payload.length; i++) { | |
bytes[i + 3] = payload[i]; | |
if (i % 2 == 0) { | |
cksum1 = (cksum1 + payload[i]) & 0xFF; | |
} | |
else { | |
cksum2 = (cksum2 + payload[i]) & 0xFF; | |
} | |
} | |
bytes[payload.length + 3] = (byte)cksum1; | |
bytes[payload.length + 4] = (byte)cksum2; | |
BluetoothGattCharacteristic characteristic = mGatt.getService(UUID.fromString(SCALE_SERVICE_UUID)).getCharacteristic(UUID.fromString(SCALE_CHARACTERISTIC_UUID)); | |
characteristic.setValue(bytes); | |
mGatt.writeCharacteristic(characteristic); | |
} | |
@Override | |
public void onServicesDiscovered(BluetoothGatt gatt, int status) { | |
BluetoothGattService service = gatt.getService(UUID.fromString(SCALE_SERVICE_UUID)); | |
Log.i("onServicesDiscovered", service.toString()); | |
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(SCALE_CHARACTERISTIC_UUID)); | |
gatt.setCharacteristicNotification(characteristic, true); | |
BluetoothGattDescriptor descriptor = characteristic.getDescriptors().get(0); | |
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); | |
gatt.writeDescriptor(descriptor); | |
// Run heartbeat every 3 seconds to keep connection alive | |
scheduler.scheduleAtFixedRate(() -> { | |
byte[] payload = {0x02,0x00,0x02,0x00}; | |
sendMessage(0, payload); | |
}, 2, 3, TimeUnit.SECONDS); | |
} | |
@Override | |
// Characteristic notification | |
public void onCharacteristicChanged(BluetoothGatt gatt, | |
BluetoothGattCharacteristic characteristic) { | |
StringBuilder sb = new StringBuilder(); | |
for (byte b : characteristic.getValue()) { | |
sb.append(String.format("%02X ", b)); | |
} | |
Log.i("onCharacteristicRead", sb.toString()); | |
if (characteristic.getValue()[2] == 7) { | |
byte[] payload = {0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d}; | |
sendMessage(11, payload); | |
} | |
if (characteristic.getValue()[2] == 8 && !notificationInfoSent) { | |
byte[] payload = {0x09,0x00,0x01,0x01,0x02,0x02,0x05,0x03,0x04}; | |
sendMessage(12, payload); | |
notificationInfoSent = true; | |
} | |
} | |
@Override | |
public void onCharacteristicRead(BluetoothGatt gatt, | |
BluetoothGattCharacteristic characteristic, | |
int status) { | |
Log.i("onCharacteristicRead", characteristic.toString()); | |
gatt.disconnect(); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment