/* * Part of Phonk http://www.phonk.io * A prototyping platform for Android devices * * Copyright (C) 2013 - 2017 Victor Diaz Barrales @victordiaz (Protocoder) * Copyright (C) 2017 - Victor Diaz Barrales @victordiaz (Phonk) * * Phonk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Phonk is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Phonk. If not, see <http://www.gnu.org/licenses/>. * */ package io.phonk.runner.apprunner.api.network; import android.annotation.SuppressLint; 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.BluetoothProfile; import android.content.Context; import java.util.List; import java.util.Queue; import java.util.UUID; import io.phonk.runner.apidoc.annotation.PhonkClass; import io.phonk.runner.apidoc.annotation.PhonkMethod; import io.phonk.runner.apidoc.annotation.PhonkMethodParam; import io.phonk.runner.apprunner.AppRunner; import io.phonk.runner.apprunner.api.ProtoBase; import io.phonk.runner.apprunner.api.common.ReturnInterface; import io.phonk.runner.apprunner.api.common.ReturnObject; import io.phonk.runner.apprunner.api.other.WhatIsRunningInterface; import io.phonk.runner.apprunner.interpreter.PhonkNativeArray; import io.phonk.runner.base.utils.MLog; @SuppressLint("NewApi") @PhonkClass public class PBluetoothLEClientBak extends ProtoBase implements WhatIsRunningInterface { private Context mContext; private final AppRunner mAppRunner; private final static String DISCONNECTED = "disconnected"; private final static String CONNECTING = "connecting"; private final static String CONNECTED = "connected"; private final static String DISCONNECTING = "disconnecting"; private BluetoothAdapter mBleAdapter; private BluetoothGatt mGatt; // private Boolean connected = false; private ReturnInterface mCallbackGattConnection; private ReturnInterface mCallbackServices; private ReturnInterface mCallbackData; private String mConnectionStatus; public PBluetoothLEClientBak(AppRunner appRunner, BluetoothAdapter bleAdapter) { super(appRunner); mAppRunner = appRunner; mContext = appRunner.getAppContext(); mBleAdapter = bleAdapter; mConnectionStatus = DISCONNECTED; } @PhonkMethod(description = "Connect to mContext bluetooth device using the mac address", example = "") @PhonkMethodParam(params = {"mac", "function(data)"}) public void connectGatt(String mac) { } // Connect to a new Device public void connectGatt(String address, boolean autoConnect) { BluetoothDevice currentDevice = mBleAdapter.getRemoteDevice(address); mGatt = currentDevice.connectGatt(mContext, autoConnect, mbluetoothListener); MLog.d(TAG, "connecting to " + address); } @PhonkMethod(description = "Disconnect the bluetooth", example = "") @PhonkMethodParam(params = {""}) public void disconnectGatt() { if (!mConnectionStatus.equals(DISCONNECTED)) { MLog.d(TAG, "disconnecting"); mGatt.close(); } } // here we get services and characteristics public void discoverServices() { mGatt.discoverServices(); } @PhonkMethod(description = "Write value to characteristic", example = "") @PhonkMethodParam(params = {"uuid", "value"}) public void writeCharacteristic(String uuid, Object value) { } @PhonkMethod(description = "Read value from characteristic", example = "") @PhonkMethodParam(params = {"uuid"}) public void readCharacteristic(String uuid) { } public void listenToCharacteristic(String UUIDService, String UUIDCharacteristic) { MLog.d(TAG, "LISTENING..."); BluetoothGattService service = mGatt.getService(UUID.fromString(UUIDService)); BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(UUIDCharacteristic)); for (BluetoothGattDescriptor bluetoothGattDescriptor : characteristic.getDescriptors()) { bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mGatt.writeDescriptor(bluetoothGattDescriptor); } mGatt.setCharacteristicNotification(characteristic, true); } @PhonkMethod(description = "Enable/Disable the bluetooth adapter", example = "") @PhonkMethodParam(params = {"boolean"}) public boolean isConnected() { return mConnectionStatus == CONNECTED; } @Override public void __stop() { disconnectGatt(); } /*********************************************************************************** * IMPL */ public PBluetoothLEClientBak onGattConnectionChanged(ReturnInterface callbackGattConnection) { mCallbackGattConnection = callbackGattConnection; return this; } public PBluetoothLEClientBak onServicesChanged(ReturnInterface callbackServices) { mCallbackServices = callbackServices; return this; } public PBluetoothLEClientBak onNewData(ReturnInterface callbackData) { mCallbackData = callbackData; return this; } // Callback that controls Connection State and Characteristic State private BluetoothGattCallback mbluetoothListener = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_DISCONNECTED) { mConnectionStatus = DISCONNECTED; } else if (newState == BluetoothProfile.STATE_CONNECTING) { mConnectionStatus = CONNECTING; } else if (newState == BluetoothProfile.STATE_CONNECTED) { mConnectionStatus = CONNECTED; } else if (newState == BluetoothProfile.STATE_DISCONNECTING) { mConnectionStatus = DISCONNECTING; } MLog.d(TAG, "connected " + mConnectionStatus); if (mCallbackGattConnection != null) { ReturnObject o = new ReturnObject(); o.put("status", mConnectionStatus); o.put("gatt", gatt); mCallbackGattConnection.event(o); } } @Override // New services discovered public void onServicesDiscovered(BluetoothGatt gatt, int status) { MLog.d(TAG, "onServicesDiscovered " + gatt + " " + status); ReturnObject ret = new ReturnObject(); if (status == BluetoothGatt.GATT_SUCCESS) { List<BluetoothGattService> services = gatt.getServices(); PhonkNativeArray retServicesArray = new PhonkNativeArray(services.size()); ret.put("services", retServicesArray); int countServices = 0; for (BluetoothGattService service : services) { MLog.d(TAG, "service " + service.getUuid() + " " + service.getType()); ReturnObject retService = new ReturnObject(); retService.put("uuid", service.getUuid()); retService.put("type", service.getType()); retServicesArray.addPE(countServices++, retService); List<BluetoothGattCharacteristic> gattCharacteristic = service.getCharacteristics(); PhonkNativeArray retCharArray = new PhonkNativeArray(gattCharacteristic.size()); retService.put("characteristics", retCharArray); int counterCharacteristics = 0; for (BluetoothGattCharacteristic characteristic : gattCharacteristic) { MLog.d(TAG, "Characteristics" + characteristic.getUuid() + " " + characteristic.getProperties() + " " + characteristic.getWriteType() + " " + characteristic.getValue()); gatt.readCharacteristic(characteristic); ReturnObject retChar = new ReturnObject(); retChar.put("uuid", characteristic.getUuid()); retChar.put("writeType", characteristic.getWriteType()); /* retChar.put("descriptors", characteristic.getDescriptors()); */ retCharArray.addPE(counterCharacteristics++, retChar); } } if (mCallbackServices != null) { mCallbackServices.event(ret); } } else { MLog.d(TAG, "onServicesDiscovered received: " + status); } } // Result of a characteristic read operation @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { MLog.d(TAG, "charRead 1" + " " + status); if (status == BluetoothGatt.GATT_SUCCESS) { short lsb = (short) (characteristic.getValue()[0] & 0xff); String val = String.valueOf(lsb); MLog.d(TAG, "charRead2" + " " + val); MLog.d(TAG, "charRead3 " + characteristic.getValue()); MLog.d(TAG, "charRead5 " + characteristic.getStringValue(0)); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); MLog.d(TAG, "characteristicChanged " + characteristic.getUuid() + " " + characteristic.getValue() + " " + characteristic.getStringValue(0)); if (mCallbackData != null) { ReturnObject r = new ReturnObject(); r.put("valueByte", characteristic.getValue()); r.put("uuid", characteristic.getUuid()); r.put("value", characteristic.getStringValue(0)); mCallbackData.event(r); } } /* @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { byte[] data = characteristic.getValue(); boolean mFirstPacket = (data[0] & 0x80) == 0x80; int mMessageCount = (((data[0] & 0x60) >> 5)); int mPendingCount = (data[0] & 0x1f); byte[] mPacket = data; ByteBuffer buffer = ByteBuffer.allocate(2); buffer.put(data[5]); buffer.put(data[6]); byte[] data2 = buffer.array(); MLog.d(TAG, "Characteristic changed." + new String(data2)); if (mCallbackData != null) { ReturnObject o = new ReturnObject(); o.put("characteristicChanged", new String(data2)); mCallbackData.event(o); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { MLog.i(TAG, "Service Discovered"); ReturnObject o = new ReturnObject(); o.put("services", status); mCallbackData.event(o); } */ }; }