package com.eveningoutpost.dexdrip; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; 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.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.activeandroid.query.Select; import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.PacketBuilder; import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadData; import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare; import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord; import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord; import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord; import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice; import com.eveningoutpost.dexdrip.Models.BgReading; import com.eveningoutpost.dexdrip.Models.Calibration; import com.eveningoutpost.dexdrip.UtilityModels.DexShareAttributes; import com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter; import com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.UUID; import rx.Observable; import rx.functions.Action1; public class ShareTest extends Activity { private final static String TAG = ShareTest.class.getSimpleName(); Button button; Button closeButton; Button readButton; Button bondButton; TextView details; private String mDeviceName; private String mDeviceAddress; private boolean is_connected = false; private boolean reconnecting = false; SharedPreferences prefs; private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private String mBluetoothDeviceAddress; private BluetoothGatt mBluetoothGatt; private ForegroundServiceStarter foregroundServiceStarter; private int mConnectionState = STATE_DISCONNECTED; private BluetoothDevice device; int mStartMode; private Context mContext = null; private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED; private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING; private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING; private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED; private BluetoothGattService mShareService; private BluetoothGattCharacteristic mAuthenticationCharacteristic; private BluetoothGattCharacteristic mSendDataCharacteristic; private BluetoothGattCharacteristic mReceiveDataCharacteristic; private BluetoothGattCharacteristic mHeartBeatCharacteristic; private BluetoothGattCharacteristic mCommandCharacteristic; private BluetoothGattCharacteristic mResponseCharacteristic; //Gatt Tasks public final int GATT_NOTHING = 0; public final int GATT_SETUP = 1; public final int GATT_WRITING_COMMANDS = 2; public final int GATT_READING_RESPONSE = 3; public int successfulWrites; //RXJAVA FUN Action1<byte[]> mDataResponseListener; public ReadDataShare mReadDataShare; public int currentGattTask; public int step; public List<byte[]> writePackets; public int recordType; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_share_test); button = (Button) findViewById(R.id.connect); closeButton = (Button) findViewById(R.id.closeConnect); bondButton = (Button) findViewById(R.id.bond); readButton = (Button) findViewById(R.id.read); details = (TextView) findViewById(R.id.connection_details); addListenerOnButton(); addListenerOnCloseButton(); IntentFilter intent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); registerReceiver(mPairReceiver, intent); } @Override public void onDestroy() { super.onDestroy(); close(); Log.w(TAG, "CLOSING CONNECTION"); } public void addListenerOnButton() { button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { attemptConnection(); } }); readButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { attemptRead(); } }); bondButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { bond(mBluetoothGatt); } }); } public void addListenerOnCloseButton() { closeButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { close(); details.setText(""); } }); } private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { mBluetoothGatt = gatt; mConnectionState = STATE_CONNECTED; ActiveBluetoothDevice.connected(); Log.w(TAG, "Connected to GATT server."); Log.w(TAG, "Connection state: Bonded - " + device.getBondState()); if (device.getBondState() == BluetoothDevice.BOND_BONDED) { currentGattTask = GATT_SETUP; mBluetoothGatt.discoverServices(); } else { device.setPin("000000".getBytes()); device.createBond(); } } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { mConnectionState = STATE_DISCONNECTED; ActiveBluetoothDevice.disconnected(); Log.w(TAG, "Disconnected from GATT server."); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.w(TAG, "Services Discovered: " + status); authenticateConnection(gatt); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.w(TAG, "Characteristic Read"); byte[] value = characteristic.getValue(); if(value != null) { Log.w(TAG, "VALUE" + value); } else { Log.w(TAG, "Characteristic was null"); } nextGattStep(); } else { Log.w(TAG, "Characteristic failed to read"); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.w(TAG, "Characteristic changed"); UUID charUuid = characteristic.getUuid(); Log.w(TAG, "Characteristic Update Received: " + charUuid); if(charUuid.compareTo(mResponseCharacteristic.getUuid()) == 0) { Log.w(TAG, "mResponseCharacteristic Update"); } if(charUuid.compareTo(mCommandCharacteristic.getUuid()) == 0) { Log.w(TAG, "mCommandCharacteristic Update"); } if(charUuid.compareTo(mHeartBeatCharacteristic.getUuid()) == 0) { Log.w(TAG, "mHeartBeatCharacteristic Update"); } if(charUuid.compareTo(mReceiveDataCharacteristic.getUuid()) == 0) { Log.w(TAG, "mReceiveDataCharacteristic Update"); byte[] value = characteristic.getValue(); if(value != null) { Log.w(TAG, "Characteristic: " + value); Log.w(TAG, "Characteristic: " + value.toString()); Log.w(TAG, "Characteristic getstring: " + characteristic.getStringValue(0)); Log.w(TAG, "SUBSCRIBED TO RESPONSE LISTENER"); Observable.just(characteristic.getValue()).subscribe(mDataResponseListener); } else { Log.w(TAG, "Characteristic was null"); } } Log.w(TAG, "NEW VALUE: " + characteristic.getValue().toString()); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { Log.w(TAG, "Wrote a discriptor, status: " + status); if(step == 2 && currentGattTask == GATT_SETUP) { setListeners(2); } else if(step == 3) { setListeners(3); } else if(step == 4) { setListeners(4); } else if(step == 5) { Log.w(TAG, "Done setting Listeners"); } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.w(TAG, "Wrote a characteristic: " + status); nextGattStep(); } }; public void attemptConnection() { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (device != null) { details.append("\nConnection state: " + " Device is not null"); mConnectionState = mBluetoothManager.getConnectionState(device, BluetoothProfile.GATT); } Log.w(TAG, "Connection state: " + mConnectionState); details.append("\nConnection state: " + mConnectionState); if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) { ActiveBluetoothDevice btDevice = new Select().from(ActiveBluetoothDevice.class) .orderBy("_ID desc") .executeSingle(); if (btDevice != null) { details.append("\nBT Device: " + btDevice.name); mDeviceName = btDevice.name; mDeviceAddress = btDevice.address; mBluetoothAdapter = mBluetoothManager.getAdapter(); boolean newConnection = true; if(newConnection) { is_connected = connect(mDeviceAddress); details.append("\nConnecting...: "); } } } } public void attemptRead() { final ReadDataShare readData = new ReadDataShare(this); final Action1<Long> systemTimeListener = new Action1<Long>() { @Override public void call(Long s) { Log.d(TAG, "Made the full round trip, got " + s + " as the system time"); Log.d("SYSTTIME", "Made the full round trip, got " + s + " as the system time"); final long addativeSystemTimeOffset = new Date().getTime() - s; Log.d(TAG, "Made the full round trip, got " + addativeSystemTimeOffset + " offset"); Log.d("SYSTTIME", "Made the full round trip, got " + addativeSystemTimeOffset + " offset"); final Action1<CalRecord[]> calRecordListener = new Action1<CalRecord[]>() { @Override public void call(CalRecord[] calRecords) { Log.d(TAG, "Made the full round trip, got " + calRecords.length + " Cal Records"); Calibration.create(calRecords, addativeSystemTimeOffset, getApplicationContext()); final Action1<SensorRecord[]> sensorRecordListener = new Action1<SensorRecord[]>() { @Override public void call(SensorRecord[] sensorRecords) { Log.d(TAG, "Made the full round trip, got " + sensorRecords.length + " Sensor Records"); BgReading.create(sensorRecords, addativeSystemTimeOffset, getApplicationContext()); final Action1<EGVRecord[]> evgRecordListener = new Action1<EGVRecord[]>() { @Override public void call(EGVRecord[] egvRecords) { Log.d(TAG, "Made the full round trip, got " + egvRecords.length + " EVG Records"); BgReading.create(egvRecords, addativeSystemTimeOffset, getApplicationContext()); } }; readData.getRecentEGVs(evgRecordListener); } }; readData.getRecentSensorRecords(sensorRecordListener); } }; readData.getRecentCalRecords(calRecordListener); } }; readData.readSystemTime(systemTimeListener); } public void bond(BluetoothGatt gatt) { reconnecting = true; attemptConnection(); } public boolean connect(final String address) { details.append("\nConnecting to device"); Log.w(TAG, "CONNECTING TO DEVICE"); if (mBluetoothAdapter == null || address == null) { details.append("\nBT adapter is null"); Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { details.append("\nTrying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { mConnectionState = STATE_CONNECTING; return true; } else { return false; } } else { device = mBluetoothAdapter.getRemoteDevice(address); device.setPin("000000".getBytes()); if (device == null) { Log.w(TAG, "Device not found. Unable to connect."); details.append("\nDevice not found. Unable to connect."); return false; } mBluetoothGatt = device.connectGatt(getApplicationContext(), true, mGattCallback); Log.w(TAG, "Trying to create a new connection."); details.append("\nTrying to create a new connection to device"); mConnectionState = STATE_CONNECTING; return true; } } public void authenticateConnection(BluetoothGatt bluetoothGatt) { Log.w(TAG, "Trying to auth"); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); String receiverSn = prefs.getString("share_key", "SM00000000").toUpperCase(); if(bluetoothGatt != null) { mBluetoothGatt = bluetoothGatt; mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService); if (mShareService != null) { mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode); if(mAuthenticationCharacteristic != null) { Log.w(TAG, "Auth Characteristic found: " + mAuthenticationCharacteristic.toString()); mAuthenticationCharacteristic.setValue((receiverSn + "000000").getBytes(StandardCharsets.US_ASCII)); currentGattTask = GATT_SETUP; step = 1; bluetoothGatt.writeCharacteristic(mAuthenticationCharacteristic); } else { Log.w(TAG, "Authentication Characteristic IS NULL"); } } else { Log.w(TAG, "CRADLE SERVICE IS NULL"); } } } public void assignCharacteristics() { mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver); mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse); mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat); mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command); mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response); } public void setListeners(int listener_number) { Log.w(TAG, "Setting Listener: #" + listener_number); if(listener_number == 1) { step = 3; setCharacteristicIndication(mReceiveDataCharacteristic); } else if(listener_number == 3) { setCharacteristicIndication(mResponseCharacteristic); step = 5; } } public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.disconnect(); } public void close() { disconnect(); if (mBluetoothGatt == null) { return; } mBluetoothGatt.close(); mBluetoothGatt = null; mConnectionState = STATE_DISCONNECTED; Log.w(TAG, "bt Disconnected"); } public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.readCharacteristic(characteristic); } public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic){ setCharacteristicNotification(characteristic, true);} public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { Log.w(TAG, "Characteristic setting notification"); mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); Log.w(TAG, "UUID FOUND: " + characteristic.getUuid()); BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG)); Log.w(TAG, "Descriptor found: " + descriptor.getUuid()); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic){ setCharacteristicIndication(characteristic, true);} public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic, boolean enabled) { Log.w(TAG, "Characteristic setting notification"); mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); Log.w(TAG, "UUID FOUND: " + characteristic.getUuid()); BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG)); Log.w(TAG, "Descriptor found: " + descriptor.getUuid()); descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR); if (state == BluetoothDevice.BOND_BONDED) { Log.d(TAG, "CALLBACK RECIEVED Bonded"); currentGattTask = GATT_SETUP; mBluetoothGatt.discoverServices(); } else if (state == BluetoothDevice.BOND_NONE){ Log.d(TAG, "CALLBACK RECIEVED: Not Bonded"); Toast.makeText(getApplicationContext(), "unBonded", Toast.LENGTH_LONG).show(); } else if (state == BluetoothDevice.BOND_BONDING) { Log.d(TAG, "CALLBACK RECIEVED: Trying to bond"); Toast.makeText(getApplicationContext(), "trying to bond", Toast.LENGTH_LONG).show(); } } } }; public void writeCommand(List<byte[]> packets, int aRecordType, Action1<byte[]> dataResponseListener) { mDataResponseListener = dataResponseListener; successfulWrites = 0; writePackets = packets; recordType = aRecordType; step = 0; currentGattTask = GATT_WRITING_COMMANDS; gattWritingStep(); } private void nextGattStep() { Log.d(TAG, "Next Gatt Step"); step++; switch (currentGattTask) { case GATT_NOTHING: Log.d(TAG, "Next NOTHING: " + step); break; case GATT_SETUP: Log.d(TAG, "Next GATT SETUP: " + step); gattSetupStep(); break; case GATT_WRITING_COMMANDS: Log.d(TAG, "Next GATT WRITING: " + step); gattWritingStep(); break; } } public void clearGattTask() { currentGattTask = GATT_NOTHING; step = 0; } private void gattSetupStep() { step = 1; assignCharacteristics(); setListeners(1); } private void gattWritingStep() { Log.d(TAG, "Writing command to the Gatt, step: " + step); int index = step; if (index <= (writePackets.size() - 1)) { Log.d(TAG, "Writing: " + writePackets.get(index) + " index: " + index); mSendDataCharacteristic.setValue(writePackets.get(index)); mBluetoothGatt.writeCharacteristic(mSendDataCharacteristic); } else { clearGattTask(); } } }